diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
 # Stack uses this directory as scratch space.
 /.stack-work/
+
+# Made by hasktags
+tags
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,22 @@
+2.9 (2025-07-30)
+
+  * Moved CHANGELOG.md to extra-doc-files stanza
+  * Added bounds to build-depends libraries
+  * Removed OverloadedStrings directives from source files
+  * Switched from putStrLn and printf to the formatting library
+  * Implemented some hlint suggestions
+  * Fixed odd range in build-depends for base
+  * Switched to the more modern prettyprinter library
+  * Tidied up a bit in the cabal file
+  * Removed extra whitespace in imports
+  * Moved Stackage snapshot up to lts-22.6
+  * Replaced (++) with (<>) in a few places
+  * Added optional GPG2 signing to appimage creation
+  * Switched from newtype-generics to OverloadedRecordDot
+  * Removed ending copyright year
+  * Fixed linuxdeploy version env variable name
+
+
 2.8 (2023-01-28)
 
   * Fix for change to the Cabal Distribution API
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2016-2023, Dino Morelli <dino@ui3.info>
+Copyright (c) 2016, Dino Morelli <dino@ui3.info>
 
 Permission to use, copy, modify, and/or distribute this software
 for any purpose with or without fee is hereby granted, provided
diff --git a/hsinstall.cabal b/hsinstall.cabal
--- a/hsinstall.cabal
+++ b/hsinstall.cabal
@@ -1,20 +1,22 @@
 cabal-version: 2.2
 
 name: hsinstall
-version: 2.8
+version: 2.9
 synopsis: Install Haskell software
-description: This is a tool for deploying software projects into directory structures suitable for installation on a system. It builds upon the `stack install` command and adds more features. It's also a tool for easier AppImage creation.
+description: This is a tool for deploying software projects into directory
+  structures suitable for installation on a system. It builds upon the `stack
+  install` command and adds more features. It's also a tool for easier AppImage
+  creation.
 category: Utility
 homepage: https://github.com/dino-/hsinstall#readme
 bug-reports: https://github.com/dino-/hsinstall/issues
 author: Dino Morelli
 maintainer: Dino Morelli <dino@ui3.info>
-copyright: 2016-2023 Dino Morelli
+copyright: 2016 Dino Morelli
 license: ISC
 license-file: LICENSE
 build-type: Simple
 extra-source-files:
-  CHANGELOG.md
   doc/hcar/hsinstall.tex
   .gitignore
   hsinstall/share/applications/hsinstall.desktop
@@ -23,6 +25,8 @@
   README.md
   stack.yaml
   stack.yaml.lock
+extra-doc-files:
+  CHANGELOG.md
 
 source-repository head
   type: git
@@ -52,9 +56,6 @@
     ScopedTypeVariables
     StandaloneDeriving
     TupleSections
-  build-depends:
-      directory
-    , filepath
   ghc-options:
     -fwarn-tabs
     -Wall
@@ -63,6 +64,12 @@
     -Wincomplete-uni-patterns
     -Wpartial-fields
     -Wredundant-constraints
+  build-depends:
+      base >=3 && <5
+    , directory >=1.3.8.1 && <1.4
+    , filepath >=1.4.100.4 && <1.5
+  other-modules:
+    Paths_hsinstall
   autogen-modules:
     Paths_hsinstall
 
@@ -74,8 +81,7 @@
       Paths_hsinstall
   hs-source-dirs:
       src/lib
-  build-depends:
-      base >=4.8 && <5.0
+  -- build-depends:
 
 executable hsinstall
   import: lang
@@ -92,14 +98,13 @@
   hs-source-dirs:
       src/app
   build-depends:
-      ansi-wl-pprint
-    , base >=4.8 && <5.0
-    , Cabal
-    , exceptions
-    , heredoc
-    , hsinstall
-    , newtype-generics
-    , optparse-applicative
-    , process
-    , safe-exceptions
-    , transformers
+      Cabal >=3.10.1.0 && <4
+    , exceptions >=0.10.7 && <1
+    , formatting >=7.2.0 && <8
+    , heredoc >=0.2.0.0 && <0.3
+    , hsinstall <3
+    , optparse-applicative >=0.18.1.0 && <0.19
+    , prettyprinter >=1.7.1 && <2
+    , process >=1.6.17.0 && <2
+    , safe-exceptions >=0.1.7.4 && <0.2
+    , transformers >=0.6.1.0 && <0.7
diff --git a/src/app/HSInstall/AppImage.hs b/src/app/HSInstall/AppImage.hs
--- a/src/app/HSInstall/AppImage.hs
+++ b/src/app/HSInstall/AppImage.hs
@@ -1,18 +1,18 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedRecordDot #-}
 
 module HSInstall.AppImage
-  ( mkAppImage, prepAppImageFiles )
+  ( mkAppImage, prepAppImageFiles
+  )
   where
 
-import Control.Monad ( unless )
-import Control.Newtype.Generics ( op )
+import Control.Monad (unless)
 import qualified System.Directory as Dir
-import System.Environment ( setEnv )
-import System.FilePath ( (</>), (<.>), takeDirectory )
-import System.Process ( callProcess )
+import System.Environment (setEnv)
+import System.FilePath ((</>), (<.>), takeDirectory)
+import System.Process (callProcess)
 
-import HSInstall.Common ( ExeFile (..), TmplDir (..), dumpStockIcon
-  , tmplDir )
+import HSInstall.Common (ExeFile (..), Signing (SigningKeyId)
+  , TmplDir (v), dumpStockIcon , tmplDir)
 import HSInstall.DeploymentInfo
   ( BinDir (..)
   , PrefixDir (..)
@@ -25,10 +25,10 @@
 
 
 desktopDir :: FilePath
-desktopDir = op TmplDir tmplDir </> "share" </> "applications"
+desktopDir = tmplDir.v </> "share" </> "applications"
 
 iconDir :: FilePath
-iconDir = op TmplDir tmplDir </> "share" </> "icons" </> "hicolor" </> "scalable" </> "apps"
+iconDir = tmplDir.v </> "share" </> "icons" </> "hicolor" </> "scalable" </> "apps"
 
 
 prepAppImageFiles :: ExeFile -> IO DesktopFileStatus
@@ -48,30 +48,35 @@
 
 newtype Arg = Arg String
 
-mkAppImage :: ExeFile -> DeploymentInfo -> DesktopFileStatus -> IO ()
+mkAppImage :: Signing -> ExeFile -> DeploymentInfo -> DesktopFileStatus -> IO ()
 
-mkAppImage exeFile di DesktopExists = do
+mkAppImage signing exeFile di DesktopExists = do
   let desktopArg = Arg ("--desktop-file=" <>
-        (desktopDir </> op ExeFile exeFile <.> "desktop"))
-  mkAppImage' exeFile di desktopArg
+        (desktopDir </> exeFile.v <.> "desktop"))
+  mkAppImage' signing exeFile di desktopArg
 
-mkAppImage exeFile di CreateNewDesktop = do
-  mkAppImage' exeFile di (Arg "--create-desktop-file")
+mkAppImage signing exeFile di CreateNewDesktop = do
+  mkAppImage' signing exeFile di (Arg "--create-desktop-file")
   -- Now copy the freshly-created .desktop file into the project sources
-  let desktopFile = op ExeFile exeFile <.> "desktop"
+  let desktopFile = exeFile.v <.> "desktop"
   Dir.createDirectoryIfMissing True desktopDir
   Dir.copyFile
-    ((op PrefixDir . prefixDir $ di) </> "share" </> "applications" </> desktopFile)
+    (di.prefixDir.v </> "share" </> "applications" </> desktopFile)
     (desktopDir </> desktopFile)
 
 
-mkAppImage' :: ExeFile -> DeploymentInfo -> Arg -> IO ()
-mkAppImage' (ExeFile exeFp) di (Arg desktopArg) = do
-  setEnv "VERSION" (prettyShow . version $ di)
+mkAppImage' :: Signing -> ExeFile -> DeploymentInfo -> Arg -> IO ()
+mkAppImage' signing (ExeFile exeFp) di (Arg desktopArg) = do
+  setEnv "LINUXDEPLOY_OUTPUT_VERSION" (prettyShow . version $ di)
+  case signing of
+    (SigningKeyId keyId) -> do
+      setEnv "LDAI_SIGN" "1"
+      setEnv "LDAI_SIGN_KEY" keyId
+    _ -> pure ()
   callProcess "linuxdeploy-x86_64.AppImage"
-    [ "--appdir=" ++ (takeDirectory . op PrefixDir . prefixDir $ di)
-    , "--executable=" <> ((op BinDir . binDir $ di) </> exeFp)
+    [ "--appdir=" <> takeDirectory di.prefixDir.v
+    , "--executable=" <> (di.binDir.v </> exeFp)
     , desktopArg
-    , "--icon-file=" ++ (iconDir </> exeFp <.> "svg")
+    , "--icon-file=" <> (iconDir </> exeFp <.> "svg")
     , "--output=appimage"
     ]
diff --git a/src/app/HSInstall/Build.hs b/src/app/HSInstall/Build.hs
--- a/src/app/HSInstall/Build.hs
+++ b/src/app/HSInstall/Build.hs
@@ -7,12 +7,12 @@
   )
   where
 
-import System.Directory ( getDirectoryContents )
-import System.Process ( callProcess )
+import System.Directory (getDirectoryContents)
+import System.Process (callProcess)
 
-import HSInstall.Common ( ExeFile (..) )
-import HSInstall.Except ( justDoIt )
-import HSInstall.Opts ( BuildMode (AppImageExe, Project) )
+import HSInstall.Common (ExeFile (..))
+import HSInstall.Except (justDoIt)
+import HSInstall.Opts (BuildMode (AppImageExe, Project))
 
 
 data BuildTool = Cabal | Stack
diff --git a/src/app/HSInstall/Common.hs b/src/app/HSInstall/Common.hs
--- a/src/app/HSInstall/Common.hs
+++ b/src/app/HSInstall/Common.hs
@@ -1,35 +1,31 @@
-{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DuplicateRecordFields #-}
 
 module HSInstall.Common
   ( ExeFile (..)
+  , Signing (..)
   , TmplDir (..)
   , dumpStockIcon
   , tmplDir
   )
   where
 
-import Control.Newtype.Generics
-import Data.Maybe ( fromMaybe )
-import GHC.Generics
-import HSInstall.Paths ( getShareDir )
-import Paths_hsinstall ( getDataDir )
-import System.Directory ( copyFile )
-import System.FilePath ( (</>), (<.>) )
+import Data.Maybe (fromMaybe)
+import HSInstall.Paths (getShareDir)
+import Paths_hsinstall (getDataDir)
+import System.Directory (copyFile)
+import System.FilePath ((</>), (<.>))
 
 
-newtype TmplDir = TmplDir FilePath
-  deriving Generic
-
-instance Newtype TmplDir
+newtype TmplDir = TmplDir { v :: FilePath }
 
 tmplDir :: TmplDir
-tmplDir = pack $ "." </> "hsinstall"
+tmplDir = TmplDir $ "." </> "hsinstall"
 
 
-newtype ExeFile = ExeFile FilePath
-  deriving Generic
+newtype ExeFile = ExeFile { v :: FilePath }
 
-instance Newtype ExeFile
+
+data Signing = SigningKeyId String | NoSignature
 
 
 dumpStockIcon :: Maybe FilePath -> IO ()
diff --git a/src/app/HSInstall/DeploymentInfo.hs b/src/app/HSInstall/DeploymentInfo.hs
--- a/src/app/HSInstall/DeploymentInfo.hs
+++ b/src/app/HSInstall/DeploymentInfo.hs
@@ -1,5 +1,4 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE DuplicateRecordFields, OverloadedRecordDot #-}
 
 module HSInstall.DeploymentInfo
   ( BinDir (..)
@@ -14,10 +13,9 @@
   )
   where
 
-import Control.Applicative ( (<|>) )
-import Control.Monad.Trans.Maybe ( MaybeT (..), runMaybeT )
-import Control.Newtype.Generics
-import Data.List ( find, isSuffixOf )
+import Control.Applicative ((<|>))
+import Control.Monad.Trans.Maybe (MaybeT (..), runMaybeT)
+import Data.List (find, isSuffixOf)
 import Distribution.Package
   ( PackageId
   , PackageIdentifier (pkgName, pkgVersion)
@@ -26,18 +24,16 @@
   ( GenericPackageDescription (packageDescription)
   , PackageDescription (package)
   )
-import Distribution.Pretty ( prettyShow )
-import Distribution.Simple.PackageDescription
-  ( readGenericPackageDescription )
-import Distribution.Types.PackageName ( unPackageName )
-import Distribution.Types.Version ( Version )
-import Distribution.Verbosity ( normal )
-import GHC.Generics hiding ( Prefix )
-import System.Directory ( getDirectoryContents )
-import System.FilePath ( (</>), (<.>) )
+import Distribution.Pretty (prettyShow)
+import Distribution.Simple.PackageDescription (readGenericPackageDescription)
+import Distribution.Types.PackageName (unPackageName)
+import Distribution.Types.Version (Version)
+import Distribution.Verbosity (normal)
+import System.Directory (getDirectoryContents)
+import System.FilePath ((</>), (<.>))
 
-import HSInstall.Build ( BuildTool, makeCabal )
-import HSInstall.Common ( ExeFile (..) )
+import HSInstall.Build (BuildTool, makeCabal)
+import HSInstall.Common (ExeFile (..))
 import HSInstall.Except
   ( HSInstallException (NoCabalFiles)
   , throwM
@@ -49,20 +45,11 @@
   )
 
 
-newtype PrefixDir = PrefixDir FilePath
-  deriving Generic
-
-instance Newtype PrefixDir
-
-newtype BinDir = BinDir FilePath
-  deriving Generic
-
-instance Newtype BinDir
+newtype PrefixDir = PrefixDir { v :: FilePath }
 
-newtype DocDir = DocDir FilePath
-  deriving Generic
+newtype BinDir = BinDir { v :: FilePath }
 
-instance Newtype DocDir
+newtype DocDir = DocDir { v :: FilePath }
 
 data DeploymentInfo = DeploymentInfo
   { prefixDir :: PrefixDir
@@ -105,5 +92,5 @@
 computePrefixDir :: PrefixOpt -> BuildMode -> PrefixDir
 computePrefixDir (Prefix prefixFp) _ = PrefixDir prefixFp
 computePrefixDir NoPrefixSpecified (AppImageExe (ExeFile exeFp)) =
-  over PrefixDir (exeFp <.>) defaultPrefix
+  PrefixDir $ exeFp <.> defaultPrefix.v
 computePrefixDir NoPrefixSpecified Project = defaultPrefix
diff --git a/src/app/HSInstall/Except.hs b/src/app/HSInstall/Except.hs
--- a/src/app/HSInstall/Except.hs
+++ b/src/app/HSInstall/Except.hs
@@ -1,6 +1,3 @@
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-
 module HSInstall.Except
   ( HSInstallException (..)
   , justDoIt
@@ -11,11 +8,11 @@
   )
   where
 
-import Control.Exception.Safe
-  ( Exception, Handler (..), Typeable, catches, catchIO, throwM )
-import Control.Monad.Catch ( MonadCatch )
-import GHC.IO.Exception ( IOException )
-import System.Exit ( die )
+import Control.Exception.Safe (Exception, Handler (..), Typeable, catches,
+  catchIO, throwM)
+import Control.Monad.Catch (MonadCatch)
+import GHC.IO.Exception (IOException)
+import System.Exit (die)
 
 
 data HSInstallException
diff --git a/src/app/HSInstall/Opts.hs b/src/app/HSInstall/Opts.hs
--- a/src/app/HSInstall/Opts.hs
+++ b/src/app/HSInstall/Opts.hs
@@ -1,6 +1,4 @@
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE QuasiQuotes #-}
+{-# LANGUAGE DuplicateRecordFields, QuasiQuotes #-}
 
 module HSInstall.Opts
   ( BuildMode (..)
@@ -12,28 +10,21 @@
   )
   where
 
-import Control.Newtype.Generics
-import Data.Version ( showVersion )
-import GHC.Generics hiding ( Prefix )
+import Data.Version (showVersion)
+import Formatting ((%+), format, formatToString)
+import Formatting.ShortFormatters (s)
 import Options.Applicative
-import Paths_hsinstall ( version )
-import System.Environment ( getProgName )
-import Text.Heredoc ( here )
-import Text.PrettyPrint.ANSI.Leijen ( string )
-import Text.Printf ( printf )
+import Paths_hsinstall (version)
+import Prettyprinter (pretty)
+import System.Environment (getProgName)
+import Text.Heredoc (here)
 
-import HSInstall.Common ( ExeFile (..) )
+import HSInstall.Common (ExeFile (..), Signing (SigningKeyId, NoSignature))
 
 
-newtype CleanSwitch = CleanSwitch Bool
-  deriving Generic
-
-instance Newtype CleanSwitch
-
-newtype DumpIconSwitch = DumpIconSwitch Bool
-  deriving Generic
+newtype CleanSwitch = CleanSwitch { v :: Bool }
 
-instance Newtype DumpIconSwitch
+newtype DumpIconSwitch = DumpIconSwitch { v :: Bool }
 
 data BuildMode = AppImageExe ExeFile | Project
 
@@ -44,9 +35,11 @@
   , optDumpIcon :: DumpIconSwitch
   , optBuildMode :: BuildMode
   , optPrefix :: PrefixOpt
+  , optSigning :: Signing
   }
 
 
+{- HLINT ignore "Functor law" -}
 parser :: Parser Options
 parser = Options
   <$> ( CleanSwitch <$> switch
@@ -60,29 +53,32 @@
         <> help "Save a default icon, unix-terminal.svg, to the current working directory"
         )
       )
-  <*> ( maybe Project (AppImageExe . ExeFile) <$> optional
-        ( strOption
-          (  long "mk-appimage"
-          <> short 'i'
-          <> metavar "EXE"
-          <> help "Prepare the AppDir structure and build an AppImage for EXE. Changes PREFIX to EXE.AppDir/usr."
-          )
+  <*> option ( AppImageExe . ExeFile <$> str )
+        (  long "mk-appimage"
+        <> short 'i'
+        <> metavar "EXE"
+        <> help "Prepare the AppDir structure and build an AppImage for EXE. Changes PREFIX to EXE.AppDir/usr."
+        <> value Project
         )
-      )
-  <*> ( maybe NoPrefixSpecified Prefix <$> optional
-        ( strOption
-          (  long "prefix"
-          <> short 'p'
-          <> metavar "DIR"
-          <> help "Install prefix directory (Default: AppDir/usr)"
-          )
+  <*> option ( Prefix <$> str )
+        (  long "prefix"
+        <> short 'p'
+        <> metavar "DIR"
+        <> help "Install prefix directory (Default: AppDir/usr)"
+        <> value NoPrefixSpecified
         )
-      )
+  <*> option ( SigningKeyId <$> str )
+        (  long "sign"
+        <> short 's'
+        <> metavar "KEY_ID"
+        <> help "Sign the AppImage with the specified GPG2 key id"
+        <> value NoSignature
+        )
 
 
 versionHelper :: String -> Parser (a -> a)
 versionHelper progName =
-  infoOption (printf "%s %s" progName (showVersion version)) $ mconcat
+  infoOption (formatToString (s %+ s) progName (showVersion version)) $ mconcat
   [ long "version"
   , help "Show version information"
   , hidden
@@ -93,13 +89,13 @@
 parseOpts = do
   pn <- getProgName
   execParser $ info (parser <**> helper <**> versionHelper pn)
-    (  header (printf "%s - Pack a haskell project into a deployable directory structure" pn)
+    (  header (formatToString (s %+ "- Pack a haskell project into a deployable directory structure") pn)
     <> footer'
     )
 
 
 footer' :: InfoMod a
-footer' = footerDoc . Just . string . printf content . showVersion $ version
+footer' = footerDoc . Just . pretty $ format content (showVersion version)
     where content = [here|OVERVIEW
 
 hsinstall is a tool for installing a Haskell software project into a directory structure for deployment. It builds upon the `stack install` and `cabal install` commands and adds these features:
@@ -144,6 +140,15 @@
 
 For more info on AppImage: https://appimage.org/
 
+If you see failure like the following when using the -s,--sign switch:
+
+    [appimage/stderr] [sign] gpgme_op_sign(gpgme_ctx, gpgme_appimage_file_data, gpgme_sig_data, GPGME_SIG_MODE_DETACH): call failed: Inappropriate ioctl for device
+
+What's happening is gpg can't figure out a way to ask for the gpg key passphrase. Try setting the env like this
+
+    $ GPG_TTY=$(tty) hsinstall ...
+
+
 TEMPLATE DIRECTORY
 
 If present, hsinstall will copy the contents of the `hsinstall` template directory into `<PREFIX>`. Here's an explanation of the hsinstall directory contents:
@@ -163,4 +168,4 @@
 
 In order to locate data files at runtime, including resources, the hsinstall project includes a library to construct the share path relative to the executable. See this source code for help with integrating this into your app: https://github.com/dino-/hsinstall/blob/master/src/lib/HSInstall/Resources.hs
 
-Version %s  Dino Morelli <dino@ui3.info>|]
+Version|] %+ s %+ " Dino Morelli <dino@ui3.info>"
diff --git a/src/app/HSInstall/System/Directory.hs b/src/app/HSInstall/System/Directory.hs
--- a/src/app/HSInstall/System/Directory.hs
+++ b/src/app/HSInstall/System/Directory.hs
@@ -1,16 +1,14 @@
-{-# LANGUAGE OverloadedStrings #-}
-
 module HSInstall.System.Directory
   ( copyTree
   )
   where
 
-import Control.Monad ( when )
-import Data.List ( (\\) )
-import System.Directory ( copyFile, createDirectoryIfMissing,
-  doesDirectoryExist, getDirectoryContents )
-import System.FilePath ( (</>) )
-import Text.Printf ( printf )
+import Control.Monad (when)
+import Data.List ((\\))
+import Formatting ((%+), fprintLn, string)
+import System.Directory (copyFile, createDirectoryIfMissing,
+  doesDirectoryExist, getDirectoryContents)
+import System.FilePath ((</>))
 
 
 {-
@@ -52,7 +50,7 @@
   let targetPath = baseTargetPath </> relativePath
 
   when chatty $
-    printf "Copying %s to %s\n" sourcePath targetPath
+    fprintLn ("Copying" %+ string %+ "to" %+ string) sourcePath targetPath
 
   if isDir
     then createDirectoryIfMissing False targetPath
diff --git a/src/app/hsinstall.hs b/src/app/hsinstall.hs
--- a/src/app/hsinstall.hs
+++ b/src/app/hsinstall.hs
@@ -1,18 +1,17 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedRecordDot #-}
 
-import Control.Monad ( when )
-import Control.Newtype.Generics ( op )
+import Control.Monad (when)
+import Formatting ((%), (%+), fprintLn, string)
 import qualified System.Directory as Dir
-import System.Exit ( exitSuccess )
-import System.FilePath ( (</>) )
-import System.IO ( BufferMode (NoBuffering),
-  hSetBuffering, stderr, stdout )
-import Text.Printf ( printf )
+import System.Exit (exitSuccess)
+import System.FilePath ((</>))
+import System.IO (BufferMode (NoBuffering),
+  hSetBuffering, stderr, stdout)
 
-import HSInstall.AppImage ( mkAppImage, prepAppImageFiles )
-import HSInstall.Build ( BuildTool, clean,
-  determineBuildTool, installBinaries )
-import HSInstall.Common ( TmplDir (..), dumpStockIcon, tmplDir )
+import HSInstall.AppImage (mkAppImage, prepAppImageFiles)
+import HSInstall.Build (BuildTool, clean,
+  determineBuildTool, installBinaries)
+import HSInstall.Common (TmplDir (v), dumpStockIcon, tmplDir)
 import HSInstall.DeploymentInfo
   ( BinDir (..)
   , DeploymentInfo (binDir, docDir, prefixDir)
@@ -20,14 +19,14 @@
   , PrefixDir (..)
   , constructDeploymentInfo
   )
-import HSInstall.Except ( withExceptionHandling )
+import HSInstall.Except (withExceptionHandling)
 import HSInstall.Opts
   ( BuildMode (AppImageExe, Project)
   , CleanSwitch (..), DumpIconSwitch (..)
   , Options (..)
   , parseOpts
   )
-import HSInstall.System.Directory ( copyTree )
+import HSInstall.System.Directory (copyTree)
 
 
 main :: IO ()
@@ -37,23 +36,23 @@
     opts <- parseOpts
 
     buildTool <- determineBuildTool
-    putStrLn $ "Build tool detected: " <> show buildTool
+    fprintLn ("Build tool detected:" %+ string) $ show buildTool
 
-    when (op DumpIconSwitch . optDumpIcon $ opts) $ dumpStockIcon Nothing >> exitSuccess
+    when opts.optDumpIcon.v $ dumpStockIcon Nothing >> exitSuccess
 
     di <- constructDeploymentInfo buildTool opts
 
-    when (op CleanSwitch . optClean $ opts) $ clean buildTool
+    when opts.optClean.v $ clean buildTool
     deployApplication buildTool (optBuildMode opts) di
     case optBuildMode opts of
-      AppImageExe exePath -> prepAppImageFiles exePath >>= mkAppImage exePath di
+      AppImageExe exePath -> prepAppImageFiles exePath >>= mkAppImage (optSigning opts) exePath di
       Project             -> return ()
 
 
 deployApplication :: BuildTool -> BuildMode -> DeploymentInfo -> IO ()
 deployApplication buildTool mode di = do
   -- Copy the binaries
-  let binFp = op BinDir . binDir $ di
+  let binFp = di.binDir.v
   Dir.createDirectoryIfMissing True binFp
   installBinaries buildTool mode binFp
 
@@ -61,14 +60,14 @@
   let licenseFile = "LICENSE"
   licenseFileExists <- Dir.doesFileExist licenseFile
   when licenseFileExists $ do
-    printf "\nCopying %s\n" licenseFile
-    let docFp = op DocDir . docDir $ di
+    fprintLn ("\nCopying" %+ string) licenseFile
+    let docFp = di.docDir.v
     Dir.createDirectoryIfMissing True docFp
     Dir.copyFile licenseFile (docFp </> licenseFile)
 
   -- Copy the static template directory
-  let tmplFp = op TmplDir tmplDir
+  let tmplFp = tmplDir.v
   tmplExists <- Dir.doesDirectoryExist tmplFp
   when tmplExists $ do
-    printf "\nCopying distribution files from template dir (%s)\n" tmplFp
-    copyTree False tmplFp (op PrefixDir . prefixDir $ di)
+    fprintLn ("\nCopying distribution files from template dir (" % string % ")") tmplFp
+    copyTree False tmplFp di.prefixDir.v
diff --git a/src/lib/HSInstall/Paths.hs b/src/lib/HSInstall/Paths.hs
--- a/src/lib/HSInstall/Paths.hs
+++ b/src/lib/HSInstall/Paths.hs
@@ -38,7 +38,7 @@
   sharePathExists <- doesDirectoryExist sharePath
   if sharePathExists
     then return sharePath
-    else fail $ "Share directory " ++ sharePath ++ " does not exist"
+    else fail $ "Share directory " <> sharePath <> " does not exist"
 
 
 stripVersion :: String -> String
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,4 +1,4 @@
-resolver: nightly-2023-01-28
+snapshot: lts-22.6
 
 packages:
 - '.'
diff --git a/stack.yaml.lock b/stack.yaml.lock
--- a/stack.yaml.lock
+++ b/stack.yaml.lock
@@ -1,12 +1,12 @@
 # This file was autogenerated by Stack.
 # You should not edit this file by hand.
 # For more information, please see the documentation at:
-#   https://docs.haskellstack.org/en/stable/lock_files
+#   https://docs.haskellstack.org/en/stable/topics/lock_files
 
 packages: []
 snapshots:
 - completed:
-    sha256: bd7b6edef8b9ad5efdf118923b9a530b9b8c2236af1b92abc3e5d9416fc1d452
-    size: 595944
-    url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2023/1/28.yaml
-  original: nightly-2023-01-28
+    sha256: 1b4c2669e26fa828451830ed4725e4d406acc25a1fa24fcc039465dd13d7a575
+    size: 714100
+    url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/6.yaml
+  original: lts-22.6
