diff --git a/mdoc.cabal b/mdoc.cabal
--- a/mdoc.cabal
+++ b/mdoc.cabal
@@ -1,10 +1,30 @@
 cabal-version:      1.18
 name:               mdoc
-version:            0.1.0.1
+version:            0.1.0.2
 license:            AGPL-3
 maintainer:         Pat Brisbin
 synopsis:           Parser and pretty-printer for the mdoc(7) language
-description:        Please see README.md
+description:
+    This library parses, represents, pretty-prints, or generates man-page content
+    using the [mdoc(7)](https://mandoc.bsd.lv/man/mdoc.7.html) language.
+    .
+    To parse a man-page and work with its data in a structured way,
+    .
+    * See 'parseMdoc' and 'Mdoc'
+    .
+    To pretty-print parsed (or constructed) man-page data,
+    .
+    * Use 'prettyMdoc' (or 'putDoc')
+    .
+    To generate a man-page from a supported parser library, check the appropriate
+    integration module,
+    .
+    * @envparse@ -- "Env.Mdoc"
+    * @opt-env-conf@ -- "OptEnvConf.Mdoc"
+    * @optparse-applicative@ -- "Options.Applicative.Mdoc"
+    .
+    An example and screenshots are present in the project [README](#readme).
+
 build-type:         Simple
 extra-source-files:
     data/man1.template
@@ -106,7 +126,6 @@
         optparse-applicative >=0.18.1.0,
         prettyprinter >=1.7.1,
         prettyprinter-ansi-terminal >=1.1.3,
-        semigroups >=0.20,
         text >=2.1.1,
         time >=1.12.2,
         zlib >=0.7.1.0
@@ -169,6 +188,7 @@
     other-modules:
         Mdoc.Gen.DescriptionSpec
         Mdoc.Gen.ExitStatusSpec
+        Mdoc.Gen.FlagSpec
         Mdoc.GenSpec
         Mdoc.Parse.MacroArgSpec
         Mdoc.Parse.MdocLineSpec
diff --git a/src/Mdoc/Dump/Env.hs b/src/Mdoc/Dump/Env.hs
--- a/src/Mdoc/Dump/Env.hs
+++ b/src/Mdoc/Dump/Env.hs
@@ -21,7 +21,7 @@
 import Mdoc.Pretty (Color (..), readColor)
 
 data Env = Env
-  { color :: Maybe Color
+  { color :: Color
   , debug :: Bool
   }
 
@@ -35,8 +35,10 @@
 envParser =
   Env.prefixed "MDOC_DUMP_"
     $ Env
-      <$> optional colorEnv
+      <$> colorEnv
       <*> switch "DEBUG" (help "Log more verbosely")
 
 colorEnv :: Parser Error Color
-colorEnv = var (eitherReader readColor) "COLOR" $ help "When to colorize the output"
+colorEnv =
+  var (eitherReader readColor) "COLOR"
+    $ help "When to colorize the output" <> def ColorDefault
diff --git a/src/Mdoc/Dump/Main.hs b/src/Mdoc/Dump/Main.hs
--- a/src/Mdoc/Dump/Main.hs
+++ b/src/Mdoc/Dump/Main.hs
@@ -19,7 +19,7 @@
 import Mdoc.Dump.Options
 import Mdoc.Input
 import Mdoc.Parse (exitParseError)
-import Mdoc.Pretty (Ann (..), Color (..), putDoc, renderPlain)
+import Mdoc.Pretty (Ann (..), putDoc, renderPlain)
 import Mdoc.UpdateMdocdate
 import Prettyprinter
 import System.Exit (exitFailure)
@@ -29,19 +29,16 @@
 main = do
   options <- parseOptions
 
-  let
-    color = fromMaybe ColorAuto options.color
-
-    postProcess mdoc =
-      if options.updateMdocdate
-        then updateMdocdate mdoc
-        else pure mdoc
+  let postProcess mdoc =
+        if options.updateMdocdate
+          then updateMdocdate mdoc
+          else pure mdoc
 
   forInputs_ options.input $ \input -> do
     case input.parsed of
       SkipParse reason ->
         when options.debug
-          $ putDoc color stderr
+          $ putDoc options.color stderr
           $ annotate AnnFile (pretty input.name)
           <> ":"
           <+> "refusing to parse"
@@ -49,7 +46,7 @@
       ParseError err -> exitParseError err
       Parsed mdoc -> do
         mdoc' <- postProcess mdoc
-        putDoc color stdout $ prettyMdoc mdoc'
+        putDoc options.color stdout $ prettyMdoc mdoc'
 
         -- NB. The --check option operates on mdoc before any --update-mdocdate
         -- changes. Unclear what the least surprising behavior is here.
@@ -61,7 +58,7 @@
 
           case diffs of
             NoDifferences ->
-              putDoc color stdout $ prettyDifferences input.name diffs
+              putDoc options.color stdout $ prettyDifferences input.name diffs
             Differences {} -> do
-              putDoc color stderr $ prettyDifferences input.name diffs
+              putDoc options.color stderr $ prettyDifferences input.name diffs
               exitFailure
diff --git a/src/Mdoc/Dump/Options.hs b/src/Mdoc/Dump/Options.hs
--- a/src/Mdoc/Dump/Options.hs
+++ b/src/Mdoc/Dump/Options.hs
@@ -20,13 +20,13 @@
 import Prelude
 
 import Mdoc.Dump.Env
-import Mdoc.Pretty (Color (..), readColor)
+import Mdoc.Pretty (Color (..), readColor, showColor)
 import Options.Applicative
 
 data Options = Options
   { check :: Bool
   , updateMdocdate :: Bool
-  , color :: Maybe Color
+  , color :: Color
   , debug :: Bool
   , input :: [FilePath]
   }
@@ -41,7 +41,7 @@
 
   pure
     (opt :: Options)
-      { color = opt.color <|> env.color
+      { color = env.color <> opt.color
       , debug = env.debug || opt.debug
       }
 
@@ -64,15 +64,15 @@
           , help "Update any $Mdocdate$ macros in the output"
           ]
       )
-    <*> optional
-      ( option
-          (eitherReader readColor)
-          ( mconcat
-              [ long "color"
-              , help "When to colorize the output"
-              , metavar "auto|always|never"
-              ]
-          )
+    <*> option
+      (eitherReader readColor)
+      ( mconcat
+          [ long "color"
+          , help "When to colorize the output"
+          , metavar "auto|always|never"
+          , value ColorDefault
+          , showDefaultWith showColor
+          ]
       )
     <*> switch
       ( mconcat
diff --git a/src/Mdoc/Gen/Argument.hs b/src/Mdoc/Gen/Argument.hs
--- a/src/Mdoc/Gen/Argument.hs
+++ b/src/Mdoc/Gen/Argument.hs
@@ -44,18 +44,15 @@
 
 renderArgumentForLong :: String -> Argument -> [MacroArg]
 renderArgumentForLong x arg@Argument {optionality} =
-  case optionality of
-    Required ->
-      [ Bare $ esc $ pack $ x <> "="
-      , Callable Ns
-      ]
-        <> renderArgument arg
-    _ ->
-      [ Bare $ esc $ pack x
-      , Callable Ns
-      , Callable Op
-      , Callable Cm
-      , Bare "="
-      , Callable Ns
-      ]
-        <> renderArgument arg
+  prefix <> [Callable Ns] <> renderArgument arg
+ where
+  prefix =
+    case optionality of
+      Required -> [Bare $ esc $ pack $ x <> "="]
+      _ ->
+        [ Bare $ esc $ pack x
+        , Callable Ns
+        , Callable Op
+        , Callable Cm
+        , Bare "="
+        ]
diff --git a/src/Mdoc/Gen/CrossRef.hs b/src/Mdoc/Gen/CrossRef.hs
--- a/src/Mdoc/Gen/CrossRef.hs
+++ b/src/Mdoc/Gen/CrossRef.hs
@@ -25,7 +25,8 @@
   deriving stock (Eq, Show)
 
 instance Ord CrossRef where
-  a `compare` b = a.section `compare` b.section <> a.name `compare` b.name
+  -- SEE ALSO is sorted section then name
+  compare = comparing $ \x -> (x.section, x.name)
 
 renderCrossRefs :: NonEmpty CrossRef -> NonEmpty MdocLine
 renderCrossRefs = go . NE.sort
diff --git a/src/Mdoc/Gen/Description.hs b/src/Mdoc/Gen/Description.hs
--- a/src/Mdoc/Gen/Description.hs
+++ b/src/Mdoc/Gen/Description.hs
@@ -58,15 +58,15 @@
     $ map switchLines switches
     <> map optionLines options
 
-switchLines :: Described Flag -> (FlagOrder, [MdocLine])
+switchLines :: Described Flag -> (Flag, [MdocLine])
 switchLines d =
-  ( flagOrder d.item
+  ( d.item
   , renderDescribedItem (`renderFlag` Nothing) d
   )
 
-optionLines :: Described Option -> (FlagOrder, [MdocLine])
+optionLines :: Described Option -> (Flag, [MdocLine])
 optionLines d =
-  ( flagOrder d.item.flag
+  ( d.item.flag
   , renderDescribedItem ((`renderFlag` (Just d.item.argument)) . (.flag)) d
   )
 
diff --git a/src/Mdoc/Gen/Environment.hs b/src/Mdoc/Gen/Environment.hs
--- a/src/Mdoc/Gen/Environment.hs
+++ b/src/Mdoc/Gen/Environment.hs
@@ -1,3 +1,11 @@
+-- |
+--
+-- Module      : Mdoc.Gen.Environment
+-- Copyright   : (c) 2026 Patrick Brisbin
+-- License     : AGPL-3
+-- Maintainer  : pbrisbin@gmail.com
+-- Stability   : experimental
+-- Portability : POSIX
 module Mdoc.Gen.Environment
   ( man1Environment
   ) where
diff --git a/src/Mdoc/Gen/ExitStatus.hs b/src/Mdoc/Gen/ExitStatus.hs
--- a/src/Mdoc/Gen/ExitStatus.hs
+++ b/src/Mdoc/Gen/ExitStatus.hs
@@ -1,3 +1,11 @@
+-- |
+--
+-- Module      : Mdoc.Gen.ExitStatus
+-- Copyright   : (c) 2026 Patrick Brisbin
+-- License     : AGPL-3
+-- Maintainer  : pbrisbin@gmail.com
+-- Stability   : experimental
+-- Portability : POSIX
 module Mdoc.Gen.ExitStatus
   ( NonZeroStatus (..)
   , renderExitStatuses
@@ -10,9 +18,9 @@
 
 data NonZeroStatus = NonZeroStatus
   { status :: Text
-  -- ^ @>0@
+  -- ^ For example, @\">0\"@
   , condition :: Text
-  -- ^ @if an error occurs@
+  -- ^ For example, @\"if an error occurs\"@
   }
   deriving stock (Eq, Generic, Show)
 
diff --git a/src/Mdoc/Gen/Flag.hs b/src/Mdoc/Gen/Flag.hs
--- a/src/Mdoc/Gen/Flag.hs
+++ b/src/Mdoc/Gen/Flag.hs
@@ -8,8 +8,6 @@
 -- Portability : POSIX
 module Mdoc.Gen.Flag
   ( Flag (..)
-  , FlagOrder
-  , flagOrder
   , renderFlag
   , renderShort
   , renderLong
@@ -29,18 +27,14 @@
   | GNUFlag String [Flag]
   deriving stock (Eq, Show)
 
-data FlagOrder = FlagOrder
-  { _byType :: Int
-  , _byNameLower :: String
-  , _byUpperThenLower :: Bool
-  }
-  deriving stock (Eq, Ord)
-
--- | Shorts before longs, capital then lower together
-flagOrder :: Flag -> FlagOrder
-flagOrder = \case
-  Flag c _ -> FlagOrder 1 [toLower c] $ isLower c
-  GNUFlag s _ -> FlagOrder 2 (map toLower s) False
+instance Ord Flag where
+  compare = comparing @(Int, String, Bool) $ \case
+    --           1. short before long
+    --           |  2. case-insensitive alphabetically
+    --           |  |            3. upper before lower
+    --           |  |            |
+    Flag c _ -> (1, [toLower c], isLower c)
+    GNUFlag s _ -> (2, map toLower s, False)
 
 renderFlag :: Flag -> Maybe Argument -> [MacroArg]
 renderFlag flag margument =
diff --git a/src/Mdoc/Gen/Optionality.hs b/src/Mdoc/Gen/Optionality.hs
--- a/src/Mdoc/Gen/Optionality.hs
+++ b/src/Mdoc/Gen/Optionality.hs
@@ -8,12 +8,31 @@
 -- Portability : POSIX
 module Mdoc.Gen.Optionality
   ( Optionality (..)
+  , opLine
   ) where
 
 import Mdoc.Prelude
 
+import Mdoc.MacroArg
+import Mdoc.MacroName
+import Mdoc.MdocLine
+
 data Optionality
   = Optional
   | Required
   | Defaulted String
   deriving stock (Eq, Show)
+
+-- | Render a macro line as @.Op@ or not
+--
+-- >>> opLine Fl ["A", Ar, "num"] Required
+-- .Fl A Ar num
+-- -A num
+--
+-- >>> opLine Fl ["A", Ar, "num"] Optional
+-- .Op Fl A Ar num
+-- [-A num]
+opLine :: MacroName -> [MacroArg] -> Optionality -> MdocLine
+opLine n args = \case
+  Required -> MacroLine n args
+  _ -> MacroLine Op $ Callable n : args
diff --git a/src/Mdoc/Gen/Synopsis.hs b/src/Mdoc/Gen/Synopsis.hs
--- a/src/Mdoc/Gen/Synopsis.hs
+++ b/src/Mdoc/Gen/Synopsis.hs
@@ -28,8 +28,7 @@
   MacroLine Nm [Bare $ esc $ pack $ m.name.primary]
     :| concat
       [ [MacroLine Bk ["-words"]]
-      , maybe [] (\cs -> [MacroLine Op [Callable Fl, Bare $ esc $ pack $ toList cs]])
-          $ shortSwitchChars m.switches
+      , maybe [] (pure . shortsLine) $ shortSwitchChars m.switches
       , mapMaybe shortOptionLine m.options
       , map snd
           $ sortOn fst
@@ -39,6 +38,9 @@
       , [MacroLine Ek []]
       ]
 
+shortsLine :: NonEmpty Char -> MdocLine
+shortsLine cs = MacroLine Op [Callable Fl, Bare $ esc $ pack $ toList cs]
+
 man5Synopsis :: Man5 -> NonEmpty MdocLine
 man5Synopsis m = renderFilesCompact m.files
 
@@ -47,37 +49,18 @@
 
 shortOptionLine :: Described Option -> Maybe MdocLine
 shortOptionLine d = withShort d.item.flag $ \c ->
-  let margs = renderShort c $ Just d.item.argument
-  in  case d.optionality of
-        Required -> MacroLine Fl margs
-        _ -> MacroLine Op $ Callable Fl : margs
+  opLine Fl (renderShort c $ Just d.item.argument) d.optionality
 
 longSwitchLine :: Described Flag -> Maybe (String, MdocLine)
 longSwitchLine d = withLong d.item $ \s ->
-  let
-    margs = renderLong s Nothing
-    mline = case d.optionality of
-      Required -> MacroLine Fl margs
-      _ -> MacroLine Op $ Callable Fl : margs
-  in
-    (s, mline)
+  (s, opLine Fl (renderLong s Nothing) d.optionality)
 
 longOptionLine :: Described Option -> Maybe (String, MdocLine)
 longOptionLine d = withLong d.item.flag $ \s ->
-  let
-    margs = renderLong s $ Just d.item.argument
-    mline = case d.optionality of
-      Required -> MacroLine Fl margs
-      _ -> MacroLine Op $ Callable Fl : margs
-  in
-    (s, mline)
+  (s, opLine Fl (renderLong s $ Just d.item.argument) d.optionality)
 
 argLine :: Described Argument -> MdocLine
-argLine d =
-  case d.optionality of
-    Required -> MacroLine Ar margs
-    Optional -> MacroLine Op $ Callable Ar : margs
-    Defaulted {} -> MacroLine Op $ Callable Ar : margs
+argLine d = opLine Ar margs d.optionality
  where
   margs
     | d.multiple = [Bare $ esc $ pack d.item.schema, "..."]
diff --git a/src/Mdoc/Interpolated.hs b/src/Mdoc/Interpolated.hs
--- a/src/Mdoc/Interpolated.hs
+++ b/src/Mdoc/Interpolated.hs
@@ -52,17 +52,14 @@
       InterpolatedLine Name -> toList v.name
       InterpolatedLine Synopsis -> toList v.synopsis
       InterpolatedLine Description -> toList v.description
-      InterpolatedLine Environment -> case v.environment of
-        Nothing -> []
-        Just es -> MacroLine Sh ["ENVIRONMENT"] : toList es
-      InterpolatedLine Files -> case v.files of
-        Nothing -> []
-        Just fs -> MacroLine Sh ["FILES"] : toList fs
+      InterpolatedLine Environment ->
+        maybe [] ((MacroLine Sh ["ENVIRONMENT"] :) . toList) v.environment
+      InterpolatedLine Files ->
+        maybe [] ((MacroLine Sh ["FILES"] :) . toList) v.files
       InterpolatedLine ExitStatus ->
         maybe [MacroLine Ex ["-std"]] toList v.exitStatus
-      InterpolatedLine SeeAlso -> case v.seeAlso of
-        Nothing -> []
-        Just crs -> MacroLine Sh ["SEE", "ALSO"] : toList crs
+      InterpolatedLine SeeAlso ->
+        maybe [] ((MacroLine Sh ["SEE", "ALSO"] :) . toList) v.seeAlso
       line -> [line]
 
 instance Interpolated Mdoc where
diff --git a/src/Mdoc/Parse.hs b/src/Mdoc/Parse.hs
--- a/src/Mdoc/Parse.hs
+++ b/src/Mdoc/Parse.hs
@@ -35,7 +35,6 @@
 import Control.Monad.State.Strict (StateT, evalState)
 import Data.Char (isSpace)
 import Data.Monoid (Last (..))
-import Data.Semigroup.Generic (GenericSemigroupMonoid (..))
 import System.Exit (exitFailure)
 import System.IO (hPutStrLn, stderr)
 import Text.Megaparsec hiding (ParseError, parseTest, runParser)
@@ -60,7 +59,7 @@
   -- ^ If in a macro definition with custom closer, this is it
   }
   deriving stock (Generic)
-  deriving (Monoid, Semigroup) via GenericSemigroupMonoid MacroState
+  deriving (Monoid, Semigroup) via Generically MacroState
 
 type ParseError = ParseErrorBundle Text Void
 
diff --git a/src/Mdoc/Pretty.hs b/src/Mdoc/Pretty.hs
--- a/src/Mdoc/Pretty.hs
+++ b/src/Mdoc/Pretty.hs
@@ -50,10 +50,26 @@
   | AnnDiffContext
 
 data Color
-  = ColorAuto
+  = -- | Behaves like 'ColorAuto' but is an identity under 'Semigroup'
+    --
+    -- This means you can give parsers this as a default, and still do (e.g.):
+    --
+    -- @
+    -- color :: Color
+    -- color = env.color <> opt.color
+    -- @
+    --
+    -- Without finding that the @opt@ default clobbers an explicit @env@.
+    ColorDefault
+  | ColorAuto
   | ColorAlways
   | ColorNever
 
+instance Semigroup Color where
+  ColorDefault <> a = a
+  a <> ColorDefault = a
+  _ <> a = a
+
 readColor :: String -> Either String Color
 readColor = \case
   "auto" -> Right ColorAuto
@@ -63,6 +79,7 @@
 
 showColor :: Color -> String
 showColor = \case
+  ColorDefault -> "auto"
   ColorAuto -> "auto"
   ColorAlways -> "always"
   ColorNever -> "never"
@@ -70,6 +87,7 @@
 putDoc :: MonadIO m => Color -> Handle -> Doc Ann -> m ()
 putDoc c h doc = do
   useColor <- case c of
+    ColorDefault -> liftIO $ hIsTerminalDevice h
     ColorAuto -> liftIO $ hIsTerminalDevice h
     ColorAlways -> pure True
     ColorNever -> pure False
diff --git a/test/Mdoc/Gen/ExitStatusSpec.hs b/test/Mdoc/Gen/ExitStatusSpec.hs
--- a/test/Mdoc/Gen/ExitStatusSpec.hs
+++ b/test/Mdoc/Gen/ExitStatusSpec.hs
@@ -1,3 +1,11 @@
+-- |
+--
+-- Module      : Mdoc.Gen.ExitStatusSpec
+-- Copyright   : (c) 2026 Patrick Brisbin
+-- License     : AGPL-3
+-- Maintainer  : pbrisbin@gmail.com
+-- Stability   : experimental
+-- Portability : POSIX
 module Mdoc.Gen.ExitStatusSpec
   ( spec
   ) where
diff --git a/test/Mdoc/Gen/FlagSpec.hs b/test/Mdoc/Gen/FlagSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Mdoc/Gen/FlagSpec.hs
@@ -0,0 +1,95 @@
+-- |
+--
+-- Module      : Mdoc.Gen.FlagSpec
+-- Copyright   : (c) 2026 Patrick Brisbin
+-- License     : AGPL-3
+-- Maintainer  : pbrisbin@gmail.com
+-- Stability   : experimental
+-- Portability : POSIX
+module Mdoc.Gen.FlagSpec
+  ( spec
+  ) where
+
+import Mdoc.Prelude
+
+import Data.List (sort)
+import Mdoc.Gen.Flag
+import Test.Hspec
+
+spec :: Spec
+spec = do
+  describe "Ord" $ do
+    it "sorts short before long, capital-then-lower together" $ do
+      let
+        unsorted =
+          [ Flag 'q' []
+          , Flag 'e' []
+          , Flag 'n' []
+          , Flag 'G' []
+          , Flag 'b' []
+          , Flag 'A' []
+          , Flag 'I' []
+          , Flag 's' []
+          , GNUFlag "binary-files" []
+          , Flag 'B' []
+          , GNUFlag "line-buffered" []
+          , Flag 'L' []
+          , Flag 'F' []
+          , GNUFlag "null" []
+          , Flag 'w' []
+          , Flag 'o' []
+          , Flag 'Z' []
+          , Flag 'x' []
+          , Flag 'E' []
+          , Flag 'v' []
+          , GNUFlag "label" []
+          , Flag 'h' []
+          , Flag 'c' []
+          , Flag 'U' []
+          , Flag 'H' []
+          , Flag 'l' []
+          , Flag 'V' []
+          , Flag 'f' []
+          , Flag 'C' [GNUFlag "context" []]
+          , Flag 'i' []
+          , Flag 'a' []
+          , Flag 'm' []
+          , Flag 'R' []
+          ]
+        sorted =
+          [ Flag 'A' []
+          , Flag 'a' []
+          , Flag 'B' []
+          , Flag 'b' []
+          , Flag 'C' [GNUFlag "context" []]
+          , Flag 'c' []
+          , Flag 'E' []
+          , Flag 'e' []
+          , Flag 'F' []
+          , Flag 'f' []
+          , Flag 'G' []
+          , Flag 'H' []
+          , Flag 'h' []
+          , Flag 'I' []
+          , Flag 'i' []
+          , Flag 'L' []
+          , Flag 'l' []
+          , Flag 'm' []
+          , Flag 'n' []
+          , Flag 'o' []
+          , Flag 'q' []
+          , Flag 'R' []
+          , Flag 's' []
+          , Flag 'U' []
+          , Flag 'V' []
+          , Flag 'v' []
+          , Flag 'w' []
+          , Flag 'x' []
+          , Flag 'Z' []
+          , GNUFlag "binary-files" []
+          , GNUFlag "label" []
+          , GNUFlag "line-buffered" []
+          , GNUFlag "null" []
+          ]
+
+      sort unsorted `shouldBe` sorted
diff --git a/test/Mdoc/Test/Fixtures.hs b/test/Mdoc/Test/Fixtures.hs
--- a/test/Mdoc/Test/Fixtures.hs
+++ b/test/Mdoc/Test/Fixtures.hs
@@ -1,5 +1,13 @@
 {-# OPTIONS_GHC -Wno-ambiguous-fields #-}
 
+-- |
+--
+-- Module      : Mdoc.Test.Fixtures
+-- Copyright   : (c) 2026 Patrick Brisbin
+-- License     : AGPL-3
+-- Maintainer  : pbrisbin@gmail.com
+-- Stability   : experimental
+-- Portability : POSIX
 module Mdoc.Test.Fixtures
   ( grepBase
   , grepOpt
