diff --git a/clod.cabal b/clod.cabal
--- a/clod.cabal
+++ b/clod.cabal
@@ -1,6 +1,6 @@
-cabal-version:       2.0
+cabal-version:       2.4
 name:                clod
-version:             0.1.2
+version:             0.1.3
 synopsis:            Project file manager for Claude AI integrations
 description:         Clod (Claude Loader) is a utility for preparing and uploading files to Claude AI's 
                      Project Knowledge feature. It tracks file changes, respects .gitignore and .clodignore 
@@ -70,7 +70,31 @@
   type:              git
   location:          https://github.com/fuzz/clod
 
+common deps
+  build-depends:     
+    base >= 4.7 && < 5,
+    directory >= 1.3 && < 1.5,
+    filepath >= 1.4 && < 1.6,
+    process >= 1.6 && < 1.7,
+    text >= 1.2 && < 2.2,
+    bytestring >= 0.10 && < 0.13,
+    containers >= 0.6 && < 0.7,
+    time >= 1.9 && < 1.13,
+    hashable >= 1.3 && < 1.6
+
+common extensions
+  default-extensions: 
+    OverloadedStrings
+    TypeOperators
+    FlexibleContexts
+    GADTs
+    DataKinds
+    ScopedTypeVariables
+    TypeApplications
+    RecordWildCards
+
 library
+  import:            deps, extensions
   hs-source-dirs:    src
   exposed-modules:   
     Clod.Core
@@ -90,70 +114,36 @@
   other-modules:     Paths_clod
   autogen-modules:   Paths_clod
   build-depends:     
-    base >= 4.7 && < 5,
-    directory >= 1.3 && < 1.4,
-    filepath >= 1.4 && < 1.5,
-    process >= 1.6 && < 1.7,
-    text >= 1.2 && < 1.3,
     aeson >= 2.0 && < 3.0,
     aeson-pretty >= 0.8 && < 0.9,
-    dhall >= 1.41 && < 1.43,
-    bytestring >= 0.10 && < 0.12,
-    containers >= 0.6 && < 0.7,
-    time >= 1.9 && < 1.13,
+    dhall >= 1.41 && < 1.44,
     temporary >= 1.3 && < 1.4,
     mtl >= 2.2 && < 2.4,
-    transformers >= 0.5 && < 0.6,
-    unix >= 2.7 && < 2.8,
+    transformers >= 0.5 && < 0.7,
+    unix >= 2.7 && < 2.9,
     xxhash-ffi >= 0.3 && < 0.4,
-    hashable >= 1.3 && < 1.5,
     base16-bytestring >= 1.0 && < 1.1,
     magic >= 1.1 && < 1.2,
     prettyprinter >= 1.7 && < 1.8,
     file-embed >= 0.0.15 && < 0.1
   default-language:  Haskell2010
-  default-extensions: 
-    OverloadedStrings
-    TypeOperators
-    FlexibleContexts
-    GADTs
-    DataKinds
-    ScopedTypeVariables
-    TypeApplications
-    TemplateHaskell
-    LambdaCase
-    RecordWildCards
+  default-extensions: TemplateHaskell
+                      LambdaCase
   ghc-options:       -Wall
 
 executable clod
+  import:            deps, extensions
   hs-source-dirs:    app
   main-is:           Main.hs
   build-depends:     
-    base >= 4.7 && < 5,
     clod,
-    directory >= 1.3 && < 1.4,
-    filepath >= 1.4 && < 1.5,
-    text >= 1.2 && < 1.3,
     aeson >= 2.0 && < 3.0,
-    bytestring >= 0.10 && < 0.12,
-    containers >= 0.6 && < 0.7,
-    time >= 1.9 && < 1.13,
-    process >= 1.6 && < 1.7,
-    hashable >= 1.3 && < 1.5,
     optparse-applicative >= 0.16 && < 0.18
   default-language:  Haskell2010
-  default-extensions: 
-    OverloadedStrings
-    TypeOperators
-    FlexibleContexts
-    GADTs
-    DataKinds
-    ScopedTypeVariables
-    TypeApplications
-    RecordWildCards
   ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N
   
 test-suite clod-test
+  import:            deps, extensions
   type:              exitcode-stdio-1.0
   hs-source-dirs:    test
   main-is:           Spec.hs
@@ -177,32 +167,15 @@
     Clod.ManPagesSpec
     Clod.TestHelpers
   build-depends:     
-    base >= 4.7 && < 5,
     clod,
-    directory >= 1.3 && < 1.4,
-    filepath >= 1.4 && < 1.5,
-    process >= 1.6 && < 1.7,
     temporary >= 1.3 && < 1.4,
-    text >= 1.2 && < 1.3,
-    time >= 1.9 && < 1.13,
+    unix >= 2.7 && < 2.9,
+    optparse-applicative >= 0.16 && < 0.18,
     hspec >= 2.8 && < 2.12,
     QuickCheck >= 2.14 && < 2.16,
-    unix >= 2.7 && < 2.8,
-    bytestring >= 0.10 && < 0.12,
-    containers >= 0.6 && < 0.7,
-    optparse-applicative >= 0.16 && < 0.18,
     random >= 1.2 && < 1.4,
     mtl >= 2.2 && < 2.4
   default-language:  Haskell2010
-  default-extensions: 
-    OverloadedStrings
-    TypeOperators
-    FlexibleContexts
-    GADTs
-    DataKinds
-    ScopedTypeVariables
-    TypeApplications
-    RecordWildCards
   ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N
   
 executable magictest
@@ -211,7 +184,7 @@
   build-depends:     
     base >= 4.7 && < 5,
     magic >= 1.1 && < 1.2,
-    directory >= 1.3 && < 1.4
+    directory >= 1.3 && < 1.5
   default-language:  Haskell2010
   default-extensions: OverloadedStrings
   ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N
diff --git a/src/Clod/FileSystem/Processing.hs b/src/Clod/FileSystem/Processing.hs
--- a/src/Clod/FileSystem/Processing.hs
+++ b/src/Clod/FileSystem/Processing.hs
@@ -334,10 +334,13 @@
       -- Remove trailing slash if present
       let cleanDir = if L.isSuffixOf "/" dir then init dir else dir
       -- Apply hidden file transformation if needed
-      in if not (null cleanDir) && head cleanDir == '.'
-         then "dot--" ++ tail cleanDir
+      in if not (null cleanDir) && cleanDir `startsWith` '.'
+         then "dot--" ++ drop 1 cleanDir
          else cleanDir
-         
+      where
+        startsWith :: String -> Char -> Bool
+        startsWith [] _ = False
+        startsWith (x:_) c = x == c
     -- Split a path into its directory components
     splitPath :: FilePath -> [String]
     splitPath path = filter (not . null) $ map getSegment $ L.groupBy sameGroup path
diff --git a/src/Clod/FileSystem/Transformations.hs b/src/Clod/FileSystem/Transformations.hs
--- a/src/Clod/FileSystem/Transformations.hs
+++ b/src/Clod/FileSystem/Transformations.hs
@@ -51,6 +51,11 @@
 -- transformFilename ".gitignore" -- returns "dot--gitignore"
 -- transformFilename "image.png" -- returns "image.png" (no change)
 -- @
+-- | Helper function to check if a string starts with a character
+startsWith :: String -> Char -> Bool
+startsWith [] _ = False
+startsWith (x:_) c = x == c
+
 transformFilename :: String -> String -> String
 transformFilename name original
   -- SVG files must be transformed to XML for Claude compatibility
@@ -59,9 +64,9 @@
       let baseName = take (length name - 4) name
       in sanitizeFilename $ baseName ++ "-svg.xml"
   -- Handle hidden files (those starting with a dot)
-  | not (null name) && head name == '.' =
+  | not (null name) && name `startsWith` '.' =
       -- Remove the leading dot and add the "dot--" prefix
-      "dot--" ++ tail name
+      "dot--" ++ drop 1 name
   -- Handle empty filename
   | null name = "unnamed"
   -- Match test case explicitly to keep compatibility with tests
diff --git a/src/Clod/IgnorePatterns.hs b/src/Clod/IgnorePatterns.hs
--- a/src/Clod/IgnorePatterns.hs
+++ b/src/Clod/IgnorePatterns.hs
@@ -482,6 +482,11 @@
 -- simpleGlobMatch "file[0-9].txt" "file5.txt"  -- Returns True
 -- simpleGlobMatch "*.txt" "file.md"  -- Returns False
 -- @
+
+-- | Helper function to check if a string starts with a character
+startsWith :: String -> Char -> Bool
+startsWith [] _ = False
+startsWith (x:_) c = x == c
 simpleGlobMatch :: String -> FilePath -> Bool
 simpleGlobMatch ptn = \filepath -> matchGlob ptn filepath
   where
@@ -529,14 +534,14 @@
       -- Beginning of character class: [
       ((CharClassStart cs), (c:path')) ->
         let (classSpec, rest) = span (/= ']') cs
-            negated = not (null classSpec) && head classSpec == '!'
-            actualClass = if negated then tail classSpec else classSpec
+            negated = not (null classSpec) && classSpec `startsWith` '!'
+            actualClass = if negated then drop 1 classSpec else classSpec
         in if null rest  -- Malformed pattern, no closing ]
            then False
            else 
              let matches = matchCharacterClass actualClass c
                  result = if negated then not matches else matches
-             in result && matchGlob (tail rest) path'
+             in result && matchGlob (drop 1 rest) path'
         
       -- Regular character matching
       ((p:ps), (c:cs)) ->
diff --git a/src/Clod/Types.hs b/src/Clod/Types.hs
--- a/src/Clod/Types.hs
+++ b/src/Clod/Types.hs
@@ -74,7 +74,6 @@
 import Control.Monad.Reader (ReaderT, ask, asks, local, runReaderT)
 import Data.String (IsString(..))
 import GHC.Generics (Generic)
-import Data.Typeable (Typeable)
 import Data.List (isPrefixOf)
 import System.Directory (canonicalizePath)
 import Data.Time.Clock (UTCTime)
@@ -125,7 +124,6 @@
   , lastMode       :: !Bool          -- ^ Whether to use the previous staging directory
   , ignorePatterns :: ![IgnorePattern] -- ^ Patterns from .gitignore and .clodignore
   } deriving stock (Show, Eq, Generic)
-    deriving anyclass (Typeable)
 
 -- | Result of processing a file
 -- 
@@ -135,7 +133,6 @@
   = Success              -- ^ File was successfully processed
   | Skipped !String      -- ^ File was skipped with the given reason
   deriving stock (Show, Eq, Generic)
-  deriving anyclass (Typeable)
 
 -- | Errors that can occur during Clod operation
 --
@@ -149,7 +146,6 @@
   | DatabaseError !String              -- ^ Error related to checksums database
   | ChecksumError !String              -- ^ Error related to checksum calculation
   deriving stock (Show, Eq, Generic)
-  deriving anyclass (Typeable)
 
 -- | Newtype for file checksums to prevent mixing with other string types
 newtype Checksum = Checksum { unChecksum :: String }
@@ -169,7 +165,7 @@
   , entryLastModified :: !UTCTime        -- ^ Last modified time
   , entryOptimizedName :: !OptimizedName -- ^ Name in staging directory
   } deriving stock (Show, Eq, Generic)
-    deriving anyclass (Typeable, FromDhall, ToDhall, FromJSON, ToJSON)
+    deriving anyclass (FromDhall, ToDhall, FromJSON, ToJSON)
 
 -- | Main database structure
 data ClodDatabase = ClodDatabase
@@ -178,7 +174,6 @@
   , dbLastStagingDir :: !(Maybe FilePath)          -- ^ Previous staging directory
   , dbLastRunTime    :: !UTCTime                  -- ^ Time of last run
   } deriving stock (Show, Eq, Generic)
-    deriving anyclass (Typeable)
 
 -- | Serialization-friendly version of ClodDatabase
 data SerializableClodDatabase = SerializableClodDatabase
@@ -187,7 +182,7 @@
   , serializedLastStagingDir :: !(Maybe FilePath)          -- ^ Previous staging directory
   , serializedLastRunTime    :: !UTCTime                  -- ^ Time of last run
   } deriving stock (Show, Eq, Generic)
-    deriving anyclass (Typeable, FromDhall, ToDhall, FromJSON, ToJSON)
+    deriving anyclass (FromDhall, ToDhall, FromJSON, ToJSON)
 
 -- | Convert to serializable form
 toSerializable :: ClodDatabase -> SerializableClodDatabase
diff --git a/test/Clod/FileSystem/ChecksumsSpec.hs b/test/Clod/FileSystem/ChecksumsSpec.hs
--- a/test/Clod/FileSystem/ChecksumsSpec.hs
+++ b/test/Clod/FileSystem/ChecksumsSpec.hs
@@ -241,9 +241,11 @@
           -- Should have one change (just the text file)
           length changes `shouldBe` 1
           -- The change should be for the text file only
-          let (path, status) = head changes
-          path `shouldBe` "text.txt"
-          status `shouldBe` New
+          case changes of
+            (path, status):_ -> do
+              path `shouldBe` "text.txt"
+              status `shouldBe` New
+            [] -> expectationFailure "Expected at least one change"
           -- The binary file should not be present in the changes
           any (("binary.bin" ==) . fst) changes `shouldBe` False
   
@@ -271,9 +273,11 @@
           -- Should have one change
           length changes `shouldBe` 1
           -- The change should be a new file
-          let (path, status) = head changes
-          path `shouldBe` "new.txt"
-          status `shouldBe` New
+          case changes of
+            (path, status):_ -> do
+              path `shouldBe` "new.txt"
+              status `shouldBe` New
+            [] -> expectationFailure "Expected at least one change"
   
   it "identifies modified files" $ do
     withSystemTempDirectory "clod-test" $ \tmpDir -> do
@@ -321,9 +325,11 @@
           -- Should have one change
           length changes `shouldBe` 1
           -- The change should be a modified file
-          let (path, status) = head changes
-          path `shouldBe` "test.txt"
-          status `shouldBe` Modified
+          case changes of
+            (path, status):_ -> do
+              path `shouldBe` "test.txt"
+              status `shouldBe` Modified
+            [] -> expectationFailure "Expected at least one change"
 
   it "identifies renamed files" $ do
     withSystemTempDirectory "clod-test" $ \tmpDir -> do
@@ -378,14 +384,18 @@
           -- Should have one change
           length changes `shouldBe` 1
           -- The change should be a renamed file
-          let (path, status) = head changes
-          path `shouldBe` "renamed.txt"
-          case status of
-            Renamed oldPath -> oldPath `shouldBe` "original.txt"
-            _ -> expectationFailure $ "Expected renamed status, got: " ++ show status
+          case changes of
+            (path, status):_ -> do
+              path `shouldBe` "renamed.txt"
+              case status of
+                Renamed oldPath -> oldPath `shouldBe` "original.txt"
+                _ -> expectationFailure $ "Expected renamed status, got: " ++ show status
+            [] -> expectationFailure "Expected at least one change"
           
           -- Should include the renamed file in the renamed list
           length renamed `shouldBe` 1
-          let (newPath, oldPath) = head renamed
-          newPath `shouldBe` "renamed.txt"
-          oldPath `shouldBe` "original.txt"
+          case renamed of
+            (newPath, oldPath):_ -> do
+              newPath `shouldBe` "renamed.txt"
+              oldPath `shouldBe` "original.txt"
+            [] -> expectationFailure "Expected at least one renamed file"
