diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,12 @@
 # Changelog
+## 0.4.4 (2024-05-03)
+- .cabal template: add autogen-modules and update tested-with ghc versions
+- publish,build: output message before cabal build
+- use simple-cmd +-+
+
+## 0.4.3.2 (2023-10-20)
+- use a cabal.project for pristine sdist/build to ignore any parent project
+- .cabal template: updated tested-with ghc versions
 
 ## 0.4.3.1 (2023-07-05)
 - fix the template file SPDX license tag and cabal-version field placement
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -70,10 +70,12 @@
 ## Help
 
 `$ hkgr --version`
+
 ```
-0.4.3.2
+0.4.4
 ```
 `$ hkgr --help`
+
 ```
 Hackage Release tool
 
@@ -171,6 +173,6 @@
 hkgr uses `cabal-install` >=2, `git`, and also `hlint` if available.
 
 ## Contribute
-`hkgr` is distributed under GPL version 3 or later.
+`hkgr` is licensed and distributed under the GPL version 3 or later.
 
 Reports and contributions are welcome at <https://github.com/juhp/hkgr>.
diff --git a/data/template.cabal.tmpl b/data/template.cabal.tmpl
--- a/data/template.cabal.tmpl
+++ b/data/template.cabal.tmpl
@@ -18,8 +18,9 @@
 -- tested-with:         GHC == 8.10.7
 --                       || == 9.0.2
 --                       || == 9.2.8
---                       || == 9.4.7
---                       || == 9.6.3
+--                       || == 9.4.8
+--                       || == 9.6.5
+--                       || == 9.8.2
 
 source-repository head
   type:                git
@@ -28,6 +29,7 @@
 executable @PROJECT@
   main-is:             Main.hs
 --  other-modules:       Paths_@PROJECT_@
+--  autogen-modules:     Paths_@PROJECT_@
   hs-source-dirs:      src
   build-depends:       base < 5,
                        @PROJECT@
diff --git a/hkgr.cabal b/hkgr.cabal
--- a/hkgr.cabal
+++ b/hkgr.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.0
 name:                hkgr
-version:             0.4.3.2
+version:             0.4.4
 synopsis:            Simple Hackage release workflow for package maintainers
 description:
             Hkgr (Hackager) is a tool to help make new releases of
@@ -13,7 +13,7 @@
 license-file:        LICENSE
 author:              Jens Petersen <juhpetersen@gmail.com>
 maintainer:          Jens Petersen <juhpetersen@gmail.com>
-copyright:           2019-2023  Jens Petersen
+copyright:           2019-2024  Jens Petersen
 category:            Util
 build-type:          Simple
 data-dir:            data
@@ -38,6 +38,7 @@
                      , extra
                      , filepath
                      , simple-cabal >= 0.1.0
+                     , simple-cmd
                      , simple-cmd-args >= 0.1.6
                      , simple-prompt >= 0.2
                      , typed-process
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -12,11 +12,9 @@
 import Data.Char
 import Data.List.Extra
 import Data.Maybe
-#if !MIN_VERSION_base(4,11,0)
-import Data.Monoid ((<>))
-#endif
 import Data.Version.Extra
 import SimpleCabal
+import SimpleCmd ((+-+))
 import SimpleCmdArgs
 import SimplePrompt (promptNonEmpty, promptPassword)
 import System.Directory
@@ -127,7 +125,7 @@
 assertTagOnBranch :: String -> IO ()
 assertTagOnBranch tag =
     whenM (null <$> cmdOut (git "branch" ["--contains", "tags/" ++ tag])) $
-    error' $ tag ++ " is no longer on branch: use --force to move it"
+    error' $ tag +-+ "is no longer on branch: use --force to move it"
 
 tagDistCmd :: Bool -> Bool -> Bool -> IO ()
 tagDistCmd existingtag force noHlint = do
@@ -137,19 +135,19 @@
   when (not force && isJust mtagHash) $ assertTagOnBranch tag
   if existingtag
     then if isNothing mtagHash
-         then error' $ "tag " ++ tag ++ " does not exist"
+         then error' $ "tag" +-+ tag +-+ "does not exist"
          else sdist force noHlint pkgid
     else do
     if isJust mtagHash && not force
       then do
       headHash <- cmdOut (git "rev-parse" ["HEAD"])
       let onHead = Just headHash == mtagHash
-      putStrLn $ "tag is " ++ (if onHead then "" else "not ") ++ "on HEAD"
+      putStrLn $ "tag is" +-+ (if onHead then "" else "not") +-+ "on HEAD"
       let tarball = sdistDir </> showPkgId pkgid <.> tarGzExt
       exists <- doesFileExist tarball
       if exists
-        then error' $ "tag " ++ tag ++ " exists: use --force to " ++
-             (if exists then "override tarball and " else "") ++ "move"
+        then error' $ "tag" +-+ tag +-+ "exists: use --force to" +-+
+             (if exists then "override tarball and" else "") +-+ "move"
         else sdist force noHlint pkgid
       else do
       git_ "tag" $ ["--force" | force] ++ [tag]
@@ -181,7 +179,7 @@
       let pkg = packageName pkgid
           cabalfile = unPackageName pkg <.> "cabal"
       unlessM (doesFileExist cabalfile) $
-        error' $ ".cabal filename differs from package name: " ++ unPackageName pkg
+        error' $ ".cabal filename differs from package name:" +-+ unPackageName pkg
       diff <- cmdOut (git "diff" ["-U0", "HEAD", cabalfile])
       when (any ("+version:" `isPrefixOf`) (lines (map toLower diff))) $
         error' "Please commit or revert the changed package Version first"
@@ -190,10 +188,10 @@
     checkNotPublished pkgid = do
       let published = sdistDir </> showPkgId pkgid <.> tarGzExt <.> "published"
       exists <- doesFileExist published
-      when exists $ error' $ showPkgId pkgid <> " was already published!!"
+      when exists $ error' $ showPkgId pkgid +-+ "was already published!!"
       let oldpublished = "dist" </> showPkgId pkgid <.> tarGzExt <.> "published"
       oldExists <- doesFileExist oldpublished
-      when oldExists $ error' $ showPkgId pkgid <> " was already published!!"
+      when oldExists $ error' $ showPkgId pkgid +-+ "was already published!!"
 
 sdistDir :: FilePath
 sdistDir = ".hkgr"
@@ -206,7 +204,7 @@
   when haveTarget $
     if force
     then removeFile target
-    else error' $ target <> " exists already!"
+    else error' $ target +-+ "exists already!"
   cwd <- getCurrentDirectory
   withTempDirectory "tmp-sdist" $ do
     git_ "clone" ["-q", "--no-checkout", "..", "."]
@@ -258,7 +256,7 @@
     git_ "push" ["origin", tag]
   userpassBS <- getUserPassword
   void $ P.readProcessInterleaved_ (P.setStdin (P.byteStringInput userpassBS) $ P.proc "cabal" ("upload" : ["--publish" | publish] ++ [tarball]))
-  putStrLn $ (if publish then "Published at " else "Uploaded to ") ++ "https://hackage.haskell.org/package/" ++ showPkgId pkgid ++ if publish then "" else "/candidate"
+  putStrLn $ (if publish then "Published at" else "Uploaded to") +-+ "https://hackage.haskell.org/package/" ++ showPkgId pkgid ++ if publish then "" else "/candidate"
   when publish $
     createFileLink (takeFileName tarball) (tarball <.> "published")
 
@@ -271,7 +269,7 @@
     if exists
       then readFile cabalConfig
       else do
-      putStrLn $ "Warning: " ++ cabalConfig ++ " not found!"
+      putStrLn $ "Warning:" +-+ cabalConfig +-+ "not found!"
       return ""
   muser <- maybeGetHackage "username" False cabalConfig
   mpasswd <- maybeGetHackage "password" True cabalConfig
@@ -281,7 +279,7 @@
     maybeGetHackage field hide cabalConfig =
       if haveCabalConfigField
         then return Nothing
-        else Just <$> prompt hide ("hackage.haskell.org " ++ field)
+        else Just <$> prompt hide ("hackage.haskell.org" +-+ field)
       where
         haveCabalConfigField :: Bool
         haveCabalConfigField =
@@ -300,7 +298,7 @@
   _out <- P.readProcessInterleaved_ (P.setStdin (P.byteStringInput userpassBS) $ P.proc "cabal" ("upload" : "--documentation" : ["--publish" | publish]))
 
   pkgid <- getPackageId
-  putStrLn $ (if publish then "Published at " else "Uploaded to ") ++ "https://hackage.haskell.org/package/" ++ showPkgId pkgid ++ if publish then "" else "/candidate"
+  putStrLn $ (if publish then "Published at" else "Uploaded to") +-+ "https://hackage.haskell.org/package/" ++ showPkgId pkgid ++ if publish then "" else "/candidate"
 
 cabal_ :: String -> [String] -> IO ()
 cabal_ c args =
@@ -316,7 +314,7 @@
 needProgram :: String -> IO ()
 needProgram prog = do
   mx <- findExecutable prog
-  unless (isJust mx) $ error' $ "program needs " ++ prog
+  unless (isJust mx) $ error' $ "program needs" +-+ prog
 -- #endif
 
 -- FIXME warning if upstream template changed (keep a versioned template copy)
@@ -356,14 +354,14 @@
       whenM (doesFileExist "CHANGELOG.md") $
         renameFile "CHANGELOG.md" "ChangeLog.md"
       unlessM (doesFileExist "README.md") $
-        writeFile "README.md" $ "# " ++ name ++ "\n"
+        writeFile "README.md" $ "#" +-+ name ++ "\n"
       unless origsetup $ do
         setup <- doesFileExist setupFile
         when setup $ removeFile setupFile
       setupCabalTemplate name
     Just cblName ->
       when (cblName /= name) $
-      putStrLn $ "Warning: " ++ cblName ++ " different to " ++ name
+      putStrLn $ "Warning:" +-+ cblName +-+ "different to" +-+ name
   haveStackCfg <- doesFileExist "stack.yaml"
   mstack <- findExecutable "stack"
   -- FIXME add stack.yaml template too
@@ -399,11 +397,11 @@
         replaceHolder "EMAIL" usermail userTemplate
         githubuser <- cmdOut $ git "config" ["--global", "github.user"]
         replaceHolder "USER" githubuser userTemplate
-        putStrLn $ userTemplate ++ " set up"
+        putStrLn $ userTemplate +-+ "set up"
       copyFile userTemplate $ name <.> "cabal"
       replaceHolder "PROJECT" name $ name <.> "cabal"
       replaceHolder "PROJECT_" (map underscore name) $ name <.> "cabal"
-      replaceHolder "SUMMARY" (name ++ " project") $ name <.> "cabal"
+      replaceHolder "SUMMARY" (name +-+ "project") $ name <.> "cabal"
       year <- cmdOut (P.proc "date" ["+%Y"])
       replaceHolder "YEAR" year $ name <.> "cabal"
       let modulePath = "src/MyLib.hs"
@@ -470,9 +468,10 @@
   let tarball = cwd </> sdistDir </> showPkgId pkgid <.> tarGzExt
   exists <- doesFileExist tarball
   unless exists $
-    error' $ "Please 'tagdist' first: " ++ tarball ++ " not found"
+    error' $ "Please 'tagdist' first:" +-+ tarball +-+ "not found"
   withTempDirectory "tmp-build" $ do
     cmd_ "tar" ["xf", tarball]
     setCurrentDirectory $ showPkgId pkgid
     addCabalProject
+    putStrLn $ "cabal building" +-+ showPkgId pkgid <.> tarGzExt
     cabal_ "build" []
