Add an optional verbose flag to the Dhall configuration.

It is OR'd with the --verbose CLI flag. Defaults to False
when omitted, via record merge with a defaults record in
readConfig.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Change-Id: Ic3d3ef408e97a2b083c910eee685e57043ee6f7e
diff --git a/src/Mulkup/Config.hs b/src/Mulkup/Config.hs
index 8356824..b1db1a9 100644
--- a/src/Mulkup/Config.hs
+++ b/src/Mulkup/Config.hs
@@ -33,7 +33,7 @@
 
 --- MulkupConfig ---
 
-data MulkupConfig = MulkupConfig {host :: Text, stashes :: [StashConfig]}
+data MulkupConfig = MulkupConfig {host :: Text, stashes :: [StashConfig], verbose :: Bool}
   deriving stock (Generic, Show)
   deriving anyclass (FromDhall)
 
@@ -41,5 +41,7 @@
 
 --- readConfig ---
 
+-- | Reads a Dhall config, merging the user's record over a defaults
+-- record so optional fields can be omitted entirely.
 readConfig :: Text -> IO MulkupConfig
-readConfig = Dhall.input auto
+readConfig text = Dhall.input auto ("{ verbose = False } // (" <> text <> ")")
diff --git a/src/Mulkup/Main.hs b/src/Mulkup/Main.hs
index 32c63ea..84aff6a 100644
--- a/src/Mulkup/Main.hs
+++ b/src/Mulkup/Main.hs
@@ -27,19 +27,20 @@
 main :: IO ()
 main = do
   flags <- execParser $ info (flagParser <**> helper) fullDesc
+  config <- readConfig "./config.dhall"
+
+  let effectiveFlags = flags & #verbose %~ (|| config ^. #verbose)
   let messageAction =
-        if verbose flags
+        if effectiveFlags ^. #verbose
           then richMessageAction
           else simpleMessageAction
 
-  config <- readConfig "./config.dhall"
-
   result <-
     main'
       & runBupstash
       & runLogAction @IO messageAction
       & runReader (config :: MulkupConfig)
-      & runReader flags
+      & runReader effectiveFlags
       & errorToIOFinal @Text
       & embedToFinal @IO
       & runFinal @IO