diff --git a/distribution-opensuse.cabal b/distribution-opensuse.cabal
--- a/distribution-opensuse.cabal
+++ b/distribution-opensuse.cabal
@@ -1,5 +1,5 @@
 name:               distribution-opensuse
-version:            1.1.4
+version:            1.2.0
 synopsis:           Types, functions, and tools to manipulate the openSUSE distribution
 description:        This library is a loose collection of types, functions, and tools that
                     users and developers of the
@@ -8,8 +8,9 @@
 license-file:       LICENSE
 author:             Peter Simons
 maintainer:         simons@cryp.to
-tested-with:        GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7
-                  , GHC == 9.0.2, GHC == 9.2.7, GHC == 9.4.4, GHC == 9.6.1
+tested-with:        GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7
+                  , GHC == 9.0.2, GHC == 9.2.8, GHC == 9.4.8, GHC == 9.6.7
+                  , GHC == 9.8.4, GHC == 9.10.3, GHC == 9.12.4
 category:           Distribution
 homepage:           https://github.com/peti/distribution-opensuse/
 bug-reports:        https://github.com/peti/distribution-opensuse/issues
@@ -40,7 +41,7 @@
   hs-source-dirs:     src
   build-depends:      base         < 5
                     , Diff
-                    , aeson
+                    , aeson >= 1.0
                     , binary
                     , bytestring
                     , containers
@@ -67,6 +68,6 @@
   type:               exitcode-stdio-1.0
   main-is:            test-strip-space.hs
   hs-source-dirs:     tests
-  build-depends:      base, distribution-opensuse
+  build-depends:      distribution-opensuse
   default-language:   Haskell2010
   ghc-options:        -threaded
diff --git a/guess-changelog.hs b/guess-changelog.hs
--- a/guess-changelog.hs
+++ b/guess-changelog.hs
@@ -3,6 +3,7 @@
 
 module Main ( main ) where
 
+import Text.Read (readMaybe)
 import OpenSuse.GuessChangeLog
 
 import Data.Set ( Set )
@@ -10,25 +11,34 @@
 import qualified Data.Text as Text
 import qualified Data.Text.IO as Text
 import Prelude hiding ( FilePath )
-import Turtle hiding ( l )
+import Turtle hiding ( l, limit )
 
-parser :: Parser (FilePath, FilePath)
+parser :: Parser (Word, FilePath, FilePath)
 parser = do
+  limit <- opt parseLimit "max-unmodified-lines" 'm'
+    "maximum number of unmodified header lines (default: 10)" <|> pure 10
   old <- argPath "old" "directory containing the old package version"
   new <- argPath "new" "directory containing the new package version"
-  pure (old,new)
+  pure (limit,old,new)
 
+parseLimit :: Text.Text -> Maybe Word
+parseLimit txt = do
+  n <- readMaybe (Text.unpack txt) :: Maybe Integer
+  if n >= 0 && n <= toInteger (maxBound :: Word)
+    then Just (fromInteger n)
+    else Nothing
+
 main :: IO ()
 main = do
-  (oldDir,newDir) <- options "Guess the change log entry between two versions of a package." parser
-  result <- guessChangeLog oldDir newDir
+  (limit,oldDir,newDir) <- options "Guess the change log entry between two versions of a package." parser
+  result <- guessChangeLog limit oldDir newDir
   case result of
     GuessedChangeLog _ txt      -> Text.putStr txt
     NoChangeLogFiles            -> eprintf "no change log files found\n"
     UndocumentedUpdate p        -> eprintf ("file "%fp%" has not changed between releases\n") p
     NoCommonChangeLogFiles l r  -> eprintf ("both directories have no files in common: "%fps%" vs. "%fps%"\n") l r
     MoreThanOneChangeLogFile p  -> eprintf ("too many changelog files: "%fps%"\n") p
-    UnmodifiedTopIsTooLarge p n -> eprintf (fp%" has more than 10 unmodified lines at top: "%d%"\n") p n
+    UnmodifiedTopIsTooLarge p n -> eprintf (fp%" has more than "%d%" unmodified lines at top: "%d%"\n") p limit n
     NotJustTopAdditions p       -> eprintf (fp%" has more edits than just adding at the top\n") p
 
 -- * Utility Functions
diff --git a/guess-changelog.md b/guess-changelog.md
--- a/guess-changelog.md
+++ b/guess-changelog.md
@@ -6,7 +6,7 @@
 
 # SYNOPSIS
 
-**guess-changelog** OLD-DIR NEW-DIR
+**guess-changelog** [**--max-unmodified-lines** N] OLD-DIR NEW-DIR
 
 # DESCRIPTION
 
@@ -44,15 +44,23 @@
   but it felt like a good idea to err on the side of caution. This case is rare
   anyways.
 
-* `guess-changelog` accepts up to 10 lines of unmodified text at the top of the
+* `guess-changelog` accepts up to 10 lines by default of unmodified text at the top of the
   upstream change log file because some people like to have a short
   introduction text there etc. If that header becomes too large, however, an
-  error is returned because we expect upstream to add text at the *top*, not in
+  error is returned (adjustable with `--max-unmodified-lines`) because we expect upstream to add text at the *top*, not in
   the middle of the file.
 
 * Upstream has edited the file in some non-trivial way other than just adding
   at the top. Sometimes people re-format old entries or rewrite URLs or fix
   typos, and in such a case it feels to risky to trust the diff.
+
+# OPTIONS
+
+**-m**, **--max-unmodified-lines** N
+: Accept at most N unmodified header lines (default: 10). N must be a
+  non-negative integer; zero requires additions at the very top of the file.
+  For example, use `guess-changelog --max-unmodified-lines 12 OLD-DIR NEW-DIR`
+  for a change log with a 12-line header. Other checks on the diff still apply.
 
 # RETURN VALUES
 
diff --git a/src/OpenSuse/GuessChangeLog.hs b/src/OpenSuse/GuessChangeLog.hs
--- a/src/OpenSuse/GuessChangeLog.hs
+++ b/src/OpenSuse/GuessChangeLog.hs
@@ -12,7 +12,7 @@
 import qualified Data.Text as Text
 import qualified Data.Text.IO as Text
 import Prelude hiding ( FilePath )
-import Turtle hiding ( l, x, stderr, stdout )
+import Turtle hiding ( l, x, stderr, stdout, limit )
 
 -- | Automatically guess the differences between to releases of a package by
 -- looking at the change log file provided by upstream. The function as
@@ -33,11 +33,18 @@
 --
 --   4. Return those additions as 'Text'.
 
-guessChangeLog :: FilePath -> FilePath -> IO GuessedChangeLog
-guessChangeLog oldDir = fmap (either id id) . guessChangeLog' oldDir
+guessChangeLog :: Word
+               -- ^ Maximum number of unmodified header lines to accept
+               -- (inclusive). Zero requires additions at the very top.
+               -> FilePath
+               -- ^ Directory containing the older release.
+               -> FilePath
+               -- ^ Directory containing the updated release.
+               -> IO GuessedChangeLog
+guessChangeLog limit oldDir = fmap (either id id) . guessChangeLog' limit oldDir
 
-guessChangeLog' :: FilePath -> FilePath -> IO (Either GuessedChangeLog GuessedChangeLog)
-guessChangeLog' oldDir newDir = runExceptT $ do
+guessChangeLog' :: Word -> FilePath -> FilePath -> IO (Either GuessedChangeLog GuessedChangeLog)
+guessChangeLog' limit oldDir newDir = runExceptT $ do
   oldCLF <- Set.fromList <$> listShell (findChangeLogFiles oldDir)
   newCLF <- Set.fromList <$> listShell (findChangeLogFiles newDir)
   when (all null [oldCLF,newCLF]) (throwError NoChangeLogFiles)
@@ -53,7 +60,7 @@
       (add,foot) = span inSecond diff
       topAddOnly = all inBoth foot
   when (all inBoth changes) (throwError (UndocumentedUpdate clf))
-  unless (length top < 10) (throwError (UnmodifiedTopIsTooLarge clf (fromIntegral (length top))))
+  unless (toInteger (length top) <= toInteger limit) (throwError (UnmodifiedTopIsTooLarge clf (fromIntegral (length top))))
   unless topAddOnly (throwError (NotJustTopAdditions clf))
   return (GuessedChangeLog clf (stripSpace (Text.unlines (map unDiff add))))
 
@@ -82,11 +89,9 @@
         -- of them, respectively, but it felt like a good idea to err on the
         -- side of caution. This case is rare anyways.
     | UnmodifiedTopIsTooLarge FilePath Word
-        -- ^ 'guessChangelog' accepts up to 10 lines of unmodified text at the
-        -- top of the upstream change log file because some people like to have
-        -- a short introduction text there etc. If that header becomes too
-        -- large, however, then we return this error because we expect upstream
-        -- to add text at the top, not in the middle of the file.
+        -- ^ The unmodified header exceeds the line limit supplied to
+        -- 'guessChangeLog'. Short introductions are allowed, but larger
+        -- headers suggest upstream added text in the middle of the file.
     | NotJustTopAdditions FilePath
         -- ^ This happens when upstream edits the file in ways other than just
         -- adding at the top. Sometimes people re-format old entries or rewrite
diff --git a/tests/guess-changelog/unmodified-header-limit.test b/tests/guess-changelog/unmodified-header-limit.test
new file mode 100644
--- /dev/null
+++ b/tests/guess-changelog/unmodified-header-limit.test
@@ -0,0 +1,24 @@
+# A twelve-line introduction exceeds the default limit, but can be accepted
+# with a custom limit. The limit is inclusive and appears in diagnostics.
+
+$$$ mkdir -p _tmp/header-limit/old _tmp/header-limit/new
+$$$ awk 'BEGIN { for (i = 1; i <= 12; i++) print "Header line " i }' > _tmp/header-limit/header
+$$$ cat _tmp/header-limit/header > _tmp/header-limit/old/CHANGELOG.md
+$$$ printf 'Old release\n' >> _tmp/header-limit/old/CHANGELOG.md
+$$$ cat _tmp/header-limit/header > _tmp/header-limit/new/CHANGELOG.md
+$$$ printf 'New release\nOld release\n' >> _tmp/header-limit/new/CHANGELOG.md
+
+$$$ cabal -v0 new-run guess-changelog -- _tmp/header-limit/old _tmp/header-limit/new
+>>>2
+CHANGELOG.md has more than 10 unmodified lines at top: 12
+>>>= 0
+
+$$$ cabal -v0 new-run guess-changelog -- --max-unmodified-lines 12 _tmp/header-limit/old _tmp/header-limit/new
+>>>
+New release
+>>>= 0
+
+$$$ cabal -v0 new-run guess-changelog -- -m 11 _tmp/header-limit/old _tmp/header-limit/new
+>>>2
+CHANGELOG.md has more than 11 unmodified lines at top: 12
+>>>= 0
diff --git a/tests/run-tests b/tests/run-tests
--- a/tests/run-tests
+++ b/tests/run-tests
@@ -1,4 +1,4 @@
 #! /bin/sh
 
 cd "$(dirname "$0")" || exit 1
-exec shelltest --execdir .
+exec shelltest --defmacro="cabal=${CABAL:-cabal}" --execdir .
