diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -7,19 +7,28 @@
 
 Breaking changes
 
-Fixes
-
 Improvements
 
+Fixes
 
 
 
 
 
 
+
 -->
 Internal/api/developer-ish changes in the hledger-lib (and hledger) packages.
 For user-visible changes, see the hledger package changelog.
+
+
+# 1.34 2024-06-01
+
+Improvements
+
+- InputOpts has a new `_defer` flag for internal use instead of overusing `strict_`
+- journalCheckBalanceAssertions has moved to JournalChecks
+
 
 # 1.33.1 2024-05-02
 
diff --git a/Hledger/Data/Balancing.hs b/Hledger/Data/Balancing.hs
--- a/Hledger/Data/Balancing.hs
+++ b/Hledger/Data/Balancing.hs
@@ -20,7 +20,6 @@
 , balanceTransactionHelper
   -- * journal balancing
 , journalBalanceTransactions
-, journalCheckBalanceAssertions
   -- * tests
 , tests_Balancing
 )
@@ -375,11 +374,6 @@
             _                          -> NaturalPrecision
         saturatedAdd a b = if maxBound - a < b then maxBound else a + b
 
-
--- | Check any balance assertions in the journal and return an error message
--- if any of them fail (or if the transaction balancing they require fails).
-journalCheckBalanceAssertions :: Journal -> Maybe String
-journalCheckBalanceAssertions = either Just (const Nothing) . journalBalanceTransactions defbalancingopts
 
 -- "Transaction balancing", including: inferring missing amounts,
 -- applying balance assignments, checking transaction balancedness,
diff --git a/Hledger/Data/JournalChecks.hs b/Hledger/Data/JournalChecks.hs
--- a/Hledger/Data/JournalChecks.hs
+++ b/Hledger/Data/JournalChecks.hs
@@ -8,7 +8,9 @@
 {-# LANGUAGE NamedFieldPuns #-}
 
 module Hledger.Data.JournalChecks (
+  journalStrictChecks,
   journalCheckAccounts,
+  journalCheckBalanceAssertions,
   journalCheckCommodities,
   journalCheckPayees,
   journalCheckPairedConversionPostings,
@@ -39,7 +41,17 @@
 import Hledger.Utils
 import Data.Ord
 import Hledger.Data.Dates (showDate)
+import Hledger.Data.Balancing (journalBalanceTransactions, defbalancingopts)
 
+-- | Run the extra -s/--strict checks on a journal, in order of priority,
+-- returning the first error message if any of them fail.
+journalStrictChecks :: Journal -> Either String ()
+journalStrictChecks j = do
+  -- keep the order of checks here synced with Check.md and Hledger.Cli.Commands.Check.Check.
+  -- balanced is checked earlier, in journalFinalise
+  journalCheckCommodities j
+  journalCheckAccounts j
+
 -- | Check that all the journal's postings are to accounts  with
 -- account directives, returning an error message otherwise.
 journalCheckAccounts :: Journal -> Either String ()
@@ -59,6 +71,12 @@
           ]) f l ex (show a) a a
         where
           (f,l,_mcols,ex) = makePostingAccountErrorExcerpt p
+
+-- | Check all balance assertions in the journal and return an error message if any of them fail.
+-- (Technically, this also tries to balance the journal and can return balancing failure errors;
+-- ensure the journal is already balanced (with journalBalanceTransactions) to avoid this.)
+journalCheckBalanceAssertions :: Journal -> Either String ()
+journalCheckBalanceAssertions = fmap (const ()) . journalBalanceTransactions defbalancingopts
 
 -- | Check that all the commodities used in this journal's postings have been declared
 -- by commodity directives, returning an error message otherwise.
diff --git a/Hledger/Data/JournalChecks/Ordereddates.hs b/Hledger/Data/JournalChecks/Ordereddates.hs
--- a/Hledger/Data/JournalChecks/Ordereddates.hs
+++ b/Hledger/Data/JournalChecks/Ordereddates.hs
@@ -9,34 +9,33 @@
 import qualified Data.Text as T (pack, unlines)
 
 import Hledger.Data.Errors (makeTransactionErrorExcerpt)
-import Hledger.Data.Transaction (transactionFile, transactionDateOrDate2)
+import Hledger.Data.Transaction (transactionFile)
 import Hledger.Data.Types
 import Hledger.Utils (textChomp)
 
-journalCheckOrdereddates :: WhichDate -> Journal -> Either String ()
-journalCheckOrdereddates whichdate j = do
+journalCheckOrdereddates :: Journal -> Either String ()
+journalCheckOrdereddates j = do
   let
     -- we check date ordering within each file, not across files
     -- note, relying on txns always being sorted by file here
     txnsbyfile = groupBy (\t1 t2 -> transactionFile t1 == transactionFile t2) $ jtxns j
-    getdate = transactionDateOrDate2 whichdate
-    compare' a b = getdate a <= getdate b
+    compare' a b = tdate a <= tdate b
   (const $ Right ()) =<< (forM txnsbyfile $ \ts ->
     case checkTransactions compare' ts of
       FoldAcc{fa_previous=Nothing} -> Right ()
       FoldAcc{fa_error=Nothing}    -> Right ()
       FoldAcc{fa_error=Just t, fa_previous=Just tprev} -> Left $ printf
         ("%s:%d:\n%s\nOrdered dates checking is enabled, and this transaction's\n"
-          ++ "date%s (%s) is out of order with the previous transaction.\n"
+          ++ "date (%s) is out of order with the previous transaction.\n"
           ++ "Consider moving this entry into date order, or adjusting its date.")
-        f l ex datenum (show $ getdate t)
+        f l ex (show $ tdate t)
         where
           (_,_,_,ex1) = makeTransactionErrorExcerpt tprev (const Nothing)
           (f,l,_,ex2) = makeTransactionErrorExcerpt t finderrcols
           -- separate the two excerpts by a space-beginning line to help flycheck-hledger parse them
           ex = T.unlines [textChomp ex1, T.pack " ", textChomp ex2]
           finderrcols _t = Just (1, Just 10)
-          datenum   = if whichdate==SecondaryDate then "2" else "")
+    )
 
 data FoldAcc a b = FoldAcc
  { fa_error    :: Maybe a
diff --git a/Hledger/Read.hs b/Hledger/Read.hs
--- a/Hledger/Read.hs
+++ b/Hledger/Read.hs
@@ -107,7 +107,6 @@
   orDieTrying,
 
   -- * Misc
-  journalStrictChecks,
   saveLatestDates,
   saveLatestDatesForFiles,
 
@@ -159,7 +158,7 @@
 -- import Hledger.Read.TimeclockReader (tests_TimeclockReader)
 import Hledger.Utils
 import Prelude hiding (getContents, writeFile)
-import Hledger.Data.JournalChecks (journalCheckAccounts, journalCheckCommodities)
+import Hledger.Data.JournalChecks (journalStrictChecks)
 
 --- ** doctest setup
 -- $setup
@@ -220,15 +219,16 @@
 -- we use the journal reader (for predictability).
 --
 readJournal :: InputOpts -> Maybe FilePath -> Text -> ExceptT String IO Journal
-readJournal iopts@InputOpts{strict_} mpath txt = do
+readJournal iopts@InputOpts{strict_, _defer} mpath txt = do
   let r :: Reader IO = fromMaybe JournalReader.reader $ findReader (mformat_ iopts) mpath
   dbg6IO "readJournal: trying reader" (rFormat r)
   j <- rReadFn r iopts (fromMaybe "(string)" mpath) txt
-  when strict_ $ liftEither $ journalStrictChecks j
+  when (strict_ && not _defer) $ liftEither $ journalStrictChecks j
   return j
 
 -- | Read a Journal from this file, or from stdin if the file path is -,
 -- with strict checks if enabled, or return an error message.
+-- (Note strict checks are disabled temporarily here when this is called by readJournalFiles).
 -- The file path can have a READER: prefix.
 --
 -- The reader (data format) to use is determined from (in priority order):
@@ -241,15 +241,14 @@
 -- generation, a rules file for converting CSV data, etc.
 --
 -- If using --new, and if latest-file writing is enabled in input options,
--- and after passing strict checks if enabled, a .latest.FILE file will be created/updated
--- (for the main file only, not for included files),
--- to remember the latest transaction date (and how many transactions on this date)
--- successfully read.
+-- and not deferred by readJournalFiles, and after passing strict checks if enabled,
+-- a .latest.FILE file will be created/updated (for the main file only, not for included files),
+-- to remember the latest transaction date processed.
 --
 readJournalFile :: InputOpts -> PrefixedFilePath -> ExceptT String IO Journal
-readJournalFile iopts@InputOpts{new_, new_save_} prefixedfile = do
+readJournalFile iopts@InputOpts{new_, new_save_, _defer} prefixedfile = do
   (j, mlatestdates) <- readJournalFileAndLatestDates iopts prefixedfile
-  when (new_ && new_save_) $ liftIO $
+  when (new_ && new_save_ && not _defer) $ liftIO $
     case mlatestdates of
       Nothing                        -> return ()
       Just (LatestDatesForFile f ds) -> saveLatestDates ds f
@@ -279,9 +278,6 @@
 
 -- | Read a Journal from each specified file path (using @readJournalFile@) 
 -- and combine them into one; or return the first error message.
--- Strict checks, if enabled, are deferred till the end.
--- Writing .latest files, if enabled, is also deferred till the end,
--- and happens only if strict checks pass.
 --
 -- Combining Journals means concatenating them, basically.
 -- The parse state resets at the start of each file, which means that
@@ -289,9 +285,16 @@
 -- They do affect included child files though.
 -- Also the final parse state saved in the Journal does span all files.
 --
+-- Strict checks, if enabled, are temporarily deferred until all files are read,
+-- to ensure they see the whole journal, and/or to avoid redundant work.
+-- (Some checks, like assertions and ordereddates, might still be doing redundant work ?)
+--
+-- Writing .latest files, if enabled, is also deferred till the end,
+-- and is done only if strict checks pass.
+--
 readJournalFiles :: InputOpts -> [PrefixedFilePath] -> ExceptT String IO Journal
-readJournalFiles iopts@InputOpts{strict_,new_,new_save_} prefixedfiles = do
-  let iopts' = iopts{strict_=False, new_save_=False}
+readJournalFiles iopts@InputOpts{strict_, new_, new_save_} prefixedfiles = do
+  let iopts' = iopts{_defer=True}
   (j, latestdatesforfiles) <-
     traceOrLogAt 6 ("readJournalFiles: "++show prefixedfiles) $
     readJournalFilesAndLatestDates iopts' prefixedfiles
@@ -306,13 +309,6 @@
 readJournalFilesAndLatestDates iopts pfs = do
   (js, lastdates) <- unzip <$> mapM (readJournalFileAndLatestDates iopts) pfs
   return (maybe def sconcat $ nonEmpty js, catMaybes lastdates)
-
--- | Run the extra -s/--strict checks on a journal,
--- returning the first error message if any of them fail.
-journalStrictChecks :: Journal -> Either String ()
-journalStrictChecks j = do
-  journalCheckAccounts j
-  journalCheckCommodities j
 
 -- | An easy version of 'readJournal' which assumes default options, and fails
 -- in the IO monad.
diff --git a/Hledger/Read/Common.hs b/Hledger/Read/Common.hs
--- a/Hledger/Read/Common.hs
+++ b/Hledger/Read/Common.hs
@@ -286,7 +286,8 @@
                     <=< withExceptT (finalErrorBundlePretty . attachSource f txt)
 
 {- HLINT ignore journalFinalise "Redundant <&>" -} -- silence this warning, the code is clearer as is
--- NB activates TH, may slow compilation ? https://github.com/ndmitchell/hlint/blob/master/README.md#customizing-the-hints
+--  note this activates TH, may slow compilation ? https://github.com/ndmitchell/hlint/blob/master/README.md#customizing-the-hints
+--
 -- | Post-process a Journal that has just been parsed or generated, in this order:
 --
 -- - add misc info (file path, read time) 
@@ -295,42 +296,60 @@
 --
 -- - apply canonical commodity styles
 --
--- - add tags from account directives to postings' tags
+-- - propagate account tags to postings
 --
--- - add forecast transactions if enabled
+-- - maybe add forecast transactions
 --
--- - add tags from account directives to postings' tags (again to affect forecast transactions)
+-- - propagate account tags to postings (again to affect forecast transactions)
 --
--- - add auto postings if enabled
+-- - maybe add auto postings
 --
--- - add tags from account directives to postings' tags (again to affect auto postings)
+-- - propagate account tags to postings (again to affect auto postings)
 --
 -- - evaluate balance assignments and balance each transaction
 --
--- - check balance assertions if enabled
+-- - maybe check balance assertions
 --
--- - infer equity postings in conversion transactions if enabled
+-- - maybe infer costs from equity postings
 --
--- - infer market prices from costs if enabled
+-- - maybe infer equity postings from costs
 --
--- - check all accounts have been declared if in strict mode
+-- - manye infer market prices from costs
 --
--- - check all commodities have been declared if in strict mode
+-- One correctness check (parseable) has already passed when this function is called.
+-- Up to four more are performed here:
 --
+--  - ordereddates (when enabled)
+--
+--  - assertions (when enabled)
+--
+--  - autobalanced (and with --strict, balanced ?), in the journalBalanceTransactions step.
+--
+-- Others (commodities, accounts..) are done later by journalStrictChecks.
+--
 journalFinalise :: InputOpts -> FilePath -> Text -> ParsedJournal -> ExceptT String IO Journal
-journalFinalise iopts@InputOpts{..} f txt pj = do
-  t <- liftIO getPOSIXTime
+journalFinalise iopts@InputOpts{auto_,balancingopts_,infer_costs_,infer_equity_,strict_,verbose_tags_,_ioDay} f txt pj = do
   let
+    BalancingOpts{commodity_styles_, ignore_assertions_} = balancingopts_
     fname = "journalFinalise " <> takeFileName f
     lbl = lbl_ fname
+    -- We want to know when certain checks have been explicitly requested with the check command,
+    -- but it does not run until later. For now, hackily inspect the command line with unsafePerformIO.
+    checking checkname = "check" `elem` args && checkname `elem` args where args = progArgs
+    -- We will check ordered dates when "check ordereddates" is used.
+    checkordereddates = checking "ordereddates"
+    -- We will check balance assertions by default, unless -I is used, but always if -s or "check assertions" are used.
+    checkassertions = not ignore_assertions_ || strict_ || checking "assertions"
+
+  t <- liftIO getPOSIXTime
   liftEither $
-    pj{jglobalcommoditystyles=fromMaybe mempty $ commodity_styles_ balancingopts_}
+    pj{jglobalcommoditystyles=fromMaybe mempty commodity_styles_}
       &   journalSetLastReadTime t                       -- save the last read time
       &   journalAddFile (f, txt)                        -- save the main file's info
       &   journalReverse                                 -- convert all lists to the order they were parsed
       &   journalAddAccountTypes                         -- build a map of all known account types
       &   journalStyleAmounts                            -- Infer and apply commodity styles (but don't round) - should be done early
-      <&> journalAddForecast (verbose_tags_) (forecastPeriod iopts pj)   -- Add forecast transactions if enabled
+      <&> journalAddForecast verbose_tags_ (forecastPeriod iopts pj)   -- Add forecast transactions if enabled
       <&> journalPostingsAddAccountTags                  -- Add account tags to postings, so they can be matched by auto postings.
       >>= journalMarkRedundantCosts                      -- Mark redundant costs, to help journalBalanceTransactions ignore them.
                                                          -- (Later, journalInferEquityFromCosts will do a similar pass, adding missing equity postings.)
@@ -342,7 +361,8 @@
        -- >>= Right . dbg0With (concatMap (T.unpack.showTransaction).jtxns)
        -- >>= \j -> deepseq (concatMap (T.unpack.showTransaction).jtxns $ j) (return j)
       <&> dbg9With (lbl "amounts after styling, forecasting, auto-posting".showJournalAmountsDebug)
-      >>= journalBalanceTransactions balancingopts_      -- infer balance assignments and missing amounts and maybe check balance assertions.
+      >>= (\j -> if checkordereddates then journalCheckOrdereddates j <&> const j else Right j)  -- check ordereddates before assertions. The outer parentheses are needed.
+      >>= journalBalanceTransactions balancingopts_{ignore_assertions_=not checkassertions}  -- infer balance assignments and missing amounts, and maybe check balance assertions.
       <&> dbg9With (lbl "amounts after transaction-balancing".showJournalAmountsDebug)
       -- <&> dbg9With (("journalFinalise amounts after styling, forecasting, auto postings, transaction balancing"<>).showJournalAmountsDebug)
       >>= journalInferCommodityStyles                    -- infer commodity styles once more now that all posting amounts are present
diff --git a/Hledger/Read/InputOptions.hs b/Hledger/Read/InputOptions.hs
--- a/Hledger/Read/InputOptions.hs
+++ b/Hledger/Read/InputOptions.hs
@@ -29,18 +29,19 @@
                                                 --   by a filename prefix. Nothing means try all.
     ,mrules_file_       :: Maybe FilePath       -- ^ a conversion rules file to use (when reading CSV)
     ,aliases_           :: [String]             -- ^ account name aliases to apply
-    ,anon_              :: Bool                 -- ^ do light obfuscation of the data. Now corresponds to --obfuscate, not the old --anon flag.
-    ,new_               :: Bool                 -- ^ read only new transactions since this file was last read
-    ,new_save_          :: Bool                 -- ^ save latest new transactions state for next time
+    ,anon_              :: Bool                 -- ^ do light obfuscation of the data ? Now corresponds to --obfuscate, not the old --anon flag.
+    ,new_               :: Bool                 -- ^ read only new transactions since this file was last read ?
+    ,new_save_          :: Bool                 -- ^ save latest new transactions state for next time ?
     ,pivot_             :: String               -- ^ use the given field's value as the account name
     ,forecast_          :: Maybe DateSpan       -- ^ span in which to generate forecast transactions
     ,verbose_tags_      :: Bool                 -- ^ add user-visible tags when generating/modifying transactions & postings ?
     ,reportspan_        :: DateSpan             -- ^ a dirty hack keeping the query dates in InputOpts. This rightfully lives in ReportSpec, but is duplicated here.
-    ,auto_              :: Bool                 -- ^ generate automatic postings when journal is parsed ?
+    ,auto_              :: Bool                 -- ^ generate extra postings according to auto posting rules ?
     ,infer_equity_      :: Bool                 -- ^ infer equity conversion postings from costs ?
     ,infer_costs_       :: Bool                 -- ^ infer costs from equity conversion postings ? distinct from BalancingOpts{infer_balancing_costs_}
-    ,balancingopts_     :: BalancingOpts        -- ^ options for balancing transactions
-    ,strict_            :: Bool                 -- ^ do extra error checking (eg, all posted accounts are declared, no prices are inferred)
+    ,balancingopts_     :: BalancingOpts        -- ^ options for transaction balancing
+    ,strict_            :: Bool                 -- ^ do extra correctness checks ?
+    ,_defer             :: Bool                 -- ^ internal flag: postpone checks, because we are processing multiple files ?
     ,_ioDay             :: Day                  -- ^ today's date, for use with forecast transactions  XXX this duplicates _rsDay, and should eventually be removed when it's not needed anymore.
  } deriving (Show)
 
@@ -61,6 +62,7 @@
     , infer_costs_       = False
     , balancingopts_     = defbalancingopts
     , strict_            = False
+    , _defer             = False
     , _ioDay             = nulldate
     }
 
diff --git a/Hledger/Read/JournalReader.hs b/Hledger/Read/JournalReader.hs
--- a/Hledger/Read/JournalReader.hs
+++ b/Hledger/Read/JournalReader.hs
@@ -291,7 +291,7 @@
 includedirectivep = do
   string "include"
   lift skipNonNewlineSpaces1
-  prefixedglob <- T.unpack <$> takeWhileP Nothing (/= '\n') -- don't consume newline yet
+  prefixedglob <- rstrip . T.unpack <$> takeWhileP Nothing (/= '\n') -- don't consume newline yet
   parentoff <- getOffset
   parentpos <- getSourcePos
   let (mprefix,glb) = splitReaderPrefix prefixedglob
diff --git a/Hledger/Read/RulesReader.hs b/Hledger/Read/RulesReader.hs
--- a/Hledger/Read/RulesReader.hs
+++ b/Hledger/Read/RulesReader.hs
@@ -838,7 +838,7 @@
                $ concatMap cbMatchers
                $ filter (isBlockActive rules record)
                $ rconditionalblocks rules
-               -- ^ XXX adjusted to not use memoized field as caller might be sending a subset of rules with just one CB (hacky)
+               -- XXX adjusted to not use memoized field as caller might be sending a subset of rules with just one CB (hacky)
   group = (read (T.unpack sgroup) :: Int) - 1 -- adjust to 0-indexing
   in atMay matchgroups group
 
diff --git a/Hledger/Reports/ReportOptions.hs b/Hledger/Reports/ReportOptions.hs
--- a/Hledger/Reports/ReportOptions.hs
+++ b/Hledger/Reports/ReportOptions.hs
@@ -230,7 +230,7 @@
 
     let formatstring = T.pack <$> maybestringopt "format" rawopts
         querystring  = map T.pack $ listofstringopt "args" rawopts  -- doesn't handle an arg like "" right
-        pretty = fromMaybe False $ alwaysneveropt "pretty" rawopts
+        pretty = fromMaybe False $ ynopt "pretty" rawopts
 
         format = case parseStringFormat <$> formatstring of
             Nothing         -> defaultBalanceLineFormat
@@ -329,8 +329,8 @@
 balanceaccumopt :: RawOpts -> BalanceAccumulation
 balanceaccumopt = fromMaybe PerPeriod . balanceAccumulationOverride
 
-alwaysneveropt :: String -> RawOpts -> Maybe Bool
-alwaysneveropt opt rawopts = case maybestringopt opt rawopts of
+ynopt :: String -> RawOpts -> Maybe Bool
+ynopt opt rawopts = case maybestringopt opt rawopts of
     Just "always" -> Just True
     Just "yes"    -> Just True
     Just "y"      -> Just True
diff --git a/Hledger/Utils/Debug.hs b/Hledger/Utils/Debug.hs
--- a/Hledger/Utils/Debug.hs
+++ b/Hledger/Utils/Debug.hs
@@ -92,6 +92,8 @@
 -- http://hackage.haskell.org/packages/archive/htrace/0.1/doc/html/Debug-HTrace.html
 -- http://hackage.haskell.org/packages/archive/traced/2009.7.20/doc/html/Debug-Traced.html
 -- https://hackage.haskell.org/package/debug
+
+{-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
 
 module Hledger.Utils.Debug (
@@ -161,7 +163,13 @@
   ,dbg9With
 
   -- * Utilities
+  ,ghcDebugSupportedInLib
+  ,GhcDebugMode(..)
+  ,ghcDebugMode
+  ,withGhcDebug'
+  ,ghcDebugPause'
   ,lbl_
+  ,progName
 
   -- * Re-exports
   -- ,module Debug.Breakpoint
@@ -176,6 +184,9 @@
 import Data.List hiding (uncons)
 -- import Debug.Breakpoint
 import Debug.Trace (trace, traceIO, traceShowId)
+#ifdef GHCDEBUG
+import GHC.Debug.Stub (pause, withGhcDebug)
+#endif
 import Safe (readDef)
 import System.Environment (getProgName)
 import System.Exit (exitFailure)
@@ -211,6 +222,63 @@
                  case take 1 $ filter ("--debug" `isPrefixOf`) progArgs of
                    ['-':'-':'d':'e':'b':'u':'g':'=':v] -> readDef 1 v
                    _                                   -> 0
+
+-- | Whether ghc-debug support is included in this build, and if so, how it will behave.
+-- When hledger is built with the ghcdebug cabal build flag (normally disabled),
+-- it can listen (on unix ?) for connections from ghc-debug clients like ghc-debug-brick,
+-- for pausing/resuming the program and inspecting memory usage and profile information.
+--
+-- This is enabled by running hledger with a negative --debug level, with three different modes:
+-- --debug=-1 - run normally (can be paused/resumed by a ghc-debug client),
+-- --debug=-2 - pause and await client commands at program start (not useful currently),
+-- --debug=-3 - pause and await client commands at program end.
+data GhcDebugMode =
+    GDNotSupported
+  | GDDisabled
+  | GDNoPause
+  | GDPauseAtStart
+  | GDPauseAtEnd
+  -- keep synced with ghcDebugMode
+  deriving (Eq,Ord,Show)
+
+-- | Is the hledger-lib package built with ghc-debug support ?
+ghcDebugSupportedInLib :: Bool
+ghcDebugSupportedInLib =
+#ifdef GHCDEBUG
+  True
+#else
+  False
+#endif
+
+-- | Should the program open a socket allowing control by ghc-debug-brick or similar ghc-debug client ?
+-- See GhcDebugMode.
+ghcDebugMode :: GhcDebugMode
+ghcDebugMode =
+  case debugLevel of
+    _ | not ghcDebugSupportedInLib -> GDNotSupported
+    (-1) -> GDNoPause
+    (-2) -> GDPauseAtStart
+    (-3) -> GDPauseAtEnd
+    _    -> GDDisabled
+    -- keep synced with GhcDebugMode
+
+-- | When ghc-debug support has been built into the program and enabled at runtime with --debug=-N,
+-- this calls ghc-debug's withGhcDebug; otherwise it's a no-op.
+withGhcDebug' =
+#ifdef GHCDEBUG
+  if ghcDebugMode > GDDisabled then withGhcDebug else id
+#else
+  id
+#endif
+
+-- | When ghc-debug support has been built into the program, this calls ghc-debug's pause, otherwise it's a no-op.
+ghcDebugPause' :: IO ()
+ghcDebugPause' =
+#ifdef GHCDEBUG
+  pause
+#else
+  return ()
+#endif
 
 -- | Trace a value with the given show function before returning it.
 traceWith :: (a -> String) -> a -> a
diff --git a/Hledger/Utils/IO.hs b/Hledger/Utils/IO.hs
--- a/Hledger/Utils/IO.hs
+++ b/Hledger/Utils/IO.hs
@@ -360,8 +360,8 @@
   no_color       <- isJust <$> lookupEnv "NO_COLOR"
   supports_color <- hSupportsANSIColor h
   let coloroption = colorOption
-  return $ coloroption `elem` ["always","yes"]
-       || (coloroption `notElem` ["never","no"] && not no_color && supports_color)
+  return $ coloroption `elem` ["always","yes","y"]
+       || (coloroption `notElem` ["never","no","n"] && not no_color && supports_color)
 
 -- | Wrap a string in ANSI codes to set and reset foreground colour.
 -- ColorIntensity is @Dull@ or @Vivid@ (ie normal and bold).
diff --git a/hledger-lib.cabal b/hledger-lib.cabal
--- a/hledger-lib.cabal
+++ b/hledger-lib.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           hledger-lib
-version:        1.33.1
+version:        1.34
 synopsis:       A library providing the core functionality of hledger
 description:    This library contains hledger's core functionality.
                 It is used by most hledger* packages so that they support the same
@@ -45,6 +45,11 @@
   type: git
   location: https://github.com/simonmichael/hledger
 
+flag ghcdebug
+  description: Build with support for attaching a ghc-debug client
+  manual: True
+  default: False
+
 library
   exposed-modules:
       Hledger
@@ -156,6 +161,10 @@
   if (!(os(windows)))
     build-depends:
         pager >=0.1.1.0
+  if (flag(ghcdebug))
+    cpp-options: -DGHCDEBUG
+    build-depends:
+        ghc-debug-stub >=0.6.0.0 && <0.7
 
 test-suite doctest
   type: exitcode-stdio-1.0
@@ -215,6 +224,10 @@
   if (!(os(windows)))
     build-depends:
         pager >=0.1.1.0
+  if (flag(ghcdebug))
+    cpp-options: -DGHCDEBUG
+    build-depends:
+        ghc-debug-stub >=0.6.0.0 && <0.7
   if impl(ghc >= 9.0) && impl(ghc < 9.2)
     buildable: False
 
@@ -277,3 +290,7 @@
   if (!(os(windows)))
     build-depends:
         pager >=0.1.1.0
+  if (flag(ghcdebug))
+    cpp-options: -DGHCDEBUG
+    build-depends:
+        ghc-debug-stub >=0.6.0.0 && <0.7
