diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,12 @@
-## [_Unreleased_](https://github.com/pbrisbin/ronn/compare/v1.0.0.0...main)
+## [_Unreleased_](https://github.com/pbrisbin/ronn/compare/ronn-v1.1.0.0...main)
+
+## [v1.1.0.0](https://github.com/pbrisbin/ronn/tree/ronn-v1.1.0.0)
+
+- Export more `...ToText` functions
+- Strengthen `ManRef` types
+- Add `ronnFilePath`
+- Un-prefix types (`RonnSection` renamed `Section`, etc)
+- Remove `.Opt` and `.Env` intermediate types
 
 ## [v1.0.0.0](https://github.com/pbrisbin/ronn/tree/v1.0.0.0)
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,93 +1,18 @@
-## Ronn
+## `ronn`
 
 [![Hackage](https://img.shields.io/hackage/v/ronn.svg?style=flat)](https://hackage.haskell.org/package/ronn)
 [![Stackage Nightly](http://stackage.org/package/ronn/badge/nightly)](http://stackage.org/nightly/package/ronn)
 [![Stackage LTS](http://stackage.org/package/ronn/badge/lts)](http://stackage.org/lts/package/ronn)
-[![CI](https://github.com/pbrisbin/ronn/actions/workflows/ci.yml/badge.svg)](https://github.com/pbrisbin/ronn/actions/workflows/ci.yml)
 
 Describe and render Ronn documentation.
 
-## Why Ronn?
-
-Ronn is a [markdown-like format][ronn-format.7] for describing man-pages. Files
-written in Ronn can be viewed as markdown (e.g. rendered on GitHub), or
-converted to Roff or HTML using the `ronn` command-line.
-
-[ronn-format.7]: https://github.com/apjanke/ronn-ng/blob/main/man/ronn-format.7.ronn
-
-There are _many_ ways to author or produce man-pages in Roff and HTML formats
-from a single source, but Ronn produces *by far* the highest-quality outputs
-from the simplest source. Tools like `man2html` or even Pandoc often produce
-sub-standard output in certain cases, or lack features such as cross-references.
-
-Here is some example Ronn:
-
-```ronn
-ronn(1) -- example ronn man-page
-================================
-
-## SYNOPSIS
-
-`ronn` [options] <argument>
-
-## DESCRIPTION
-
-This is an example man-page to show how rendering the AST Looks
-
-## OPTIONS
-
-  * `-h`, `--help`:
-    Display this help
-
-  * `-o`, `--output`=<FILE>:
-    Output to `FILE`
-
-## ENVIRONMENT
-
-  * `HOME`:
-    User's HOME directory
-
-    Some further details:
-
-      * foo:
-        The foo
-
-      * bar:
-        The bar
-
-## SEE ALSO
-
-**markdown(7)**, **roff(7)**
-```
-
-Here is it rendered to Roff and opened with `man`:
-
-![](./examples/roff.png)
-
-And here it is rendered to HTML:
-
-![](./examples/html.png)
-
-This package contains the `Ronn` AST type and a rendering function. Companion
-packages are planned to automatically convert any `optparse-applicative`,
-`envparse`, or `opt-env-conf` `Parser` type into a `Ronn` value. This will allow
-any application using one of these libraries to maintain high-quality man-pages
-automatically.
-
 ## Usage
 
-For an example of building an AST by hand, and what the rendered `Text` looks
-like, see the [test suite](./tests/Ronn/RenderSpec.hs)
-
-Once you've created a `.ronn` file from the rendered `Text`, you can use the
-[`ronn-ng`][ronn-ng] gem produce a high-quality man-page and HTML:
-
-```console
-% ronn --style toc --roff --html path/*.ronn
-```
+See [the test][test] and [the result][golden].
 
-[ronn-ng]: https://github.com/apjanke/ronn-ng
+[test]: ./ronn/tests/Ronn/RenderSpec.hs
+[golden]: ./doc/ronn.1.ronn
 
 ---
 
-[LICENSE](./LICENSE) | [CHANGELOG](./CHANGELOG.md)
+[CHANGELOG](./CHANGELOG.md)
diff --git a/ronn.cabal b/ronn.cabal
--- a/ronn.cabal
+++ b/ronn.cabal
@@ -1,6 +1,6 @@
 cabal-version:   1.18
 name:            ronn
-version:         1.0.0.0
+version:         1.1.0.0
 license:         AGPL-3
 maintainer:      Pat Brisbin
 homepage:        https://github.com/pbrisbin/ronn#readme
@@ -22,8 +22,7 @@
         Ronn
         Ronn.Argument
         Ronn.AST
-        Ronn.Env
-        Ronn.Opt
+        Ronn.ManRef
         Ronn.Render
 
     hs-source-dirs:     src
@@ -56,6 +55,7 @@
     main-is:            Main.hs
     hs-source-dirs:     tests
     other-modules:
+        Ronn.ManRefSpec
         Ronn.RenderSpec
         Paths_ronn
 
@@ -76,7 +76,9 @@
 
     build-depends:
         base >=4.16.4.0 && <5,
+        filepath >=1.4.2.2,
         hspec >=2.9.7,
+        hspec-golden >=0.2.1.0,
         ronn,
         text >=1.2.5.0
 
diff --git a/src/Ronn.hs b/src/Ronn.hs
--- a/src/Ronn.hs
+++ b/src/Ronn.hs
@@ -7,11 +7,54 @@
 -- Stability   : experimental
 -- Portability : POSIX
 module Ronn
-  ( module X
+  ( module Ronn.AST
+  , module Ronn.Render
+  , ronnFilePath
+
+    -- * Higher-level builders
+  , synopsisSection
+  , seeAlsoSection
+  , oneLineSection
+  , definitionsSection
   )
 where
 
-import Ronn.AST as X
-import Ronn.Env as X
-import Ronn.Opt as X
-import Ronn.Render as X
+import Prelude
+
+import Data.List (intersperse, sort)
+import Data.Text (Text, unpack)
+import Ronn.AST
+import Ronn.Render
+
+ronnFilePath :: Ronn -> FilePath
+ronnFilePath ronn =
+  unpack ref.name <> "." <> show (manSectionNumber ref.section) <> ".ronn"
+ where
+  ref = ronn.name
+
+synopsisSection :: Text -> [Part] -> Section
+synopsisSection name = oneLineSection "SYNOPSIS" . (Code (Raw name) :)
+
+seeAlsoSection :: [ManRef] -> Section
+seeAlsoSection refs =
+  oneLineSection
+    "SEE ALSO"
+    [ mconcat $
+        intersperse ", " $
+          map Ref $
+            sort refs
+    ]
+
+oneLineSection :: Text -> [Part] -> Section
+oneLineSection name ps =
+  Section
+    { name
+    , content = [Groups [Lines [Line ps]]]
+    }
+
+definitionsSection :: Text -> [Definition] -> Section
+definitionsSection name definitions =
+  Section
+    { name
+    , content = [Definitions definitions]
+    }
diff --git a/src/Ronn/AST.hs b/src/Ronn/AST.hs
--- a/src/Ronn/AST.hs
+++ b/src/Ronn/AST.hs
@@ -8,12 +8,12 @@
 -- Portability : POSIX
 module Ronn.AST
   ( Ronn (..)
-  , RonnSection (..)
-  , RonnContent (..)
-  , RonnDefinition (..)
-  , RonnGroup (..)
-  , RonnLine (..)
-  , RonnPart (..)
+  , Section (..)
+  , Content (..)
+  , Definition (..)
+  , Group (..)
+  , Line (..)
+  , Part (..)
 
     -- * References
   , ManRef (..)
@@ -25,89 +25,79 @@
 
 import Data.String (IsString (..))
 import Data.Text (Text, pack)
+import Ronn.ManRef
 
 data Ronn = Ronn
   { name :: ManRef
-  , description :: [RonnPart]
-  , sections :: [RonnSection]
+  , description :: [Part]
+  , sections :: [Section]
   }
 
-data RonnSection = RonnSection
+data Section = Section
   { name :: Text
-  , content :: [RonnContent]
+  , content :: [Content]
   }
 
-data RonnContent
-  = RonnDefinitions [RonnDefinition]
-  | RonnGroups [RonnGroup]
+data Content
+  = Definitions [Definition]
+  | Groups [Group]
 
-instance IsString RonnContent where
-  fromString = RonnGroups . pure . fromString
+instance IsString Content where
+  fromString = Groups . pure . fromString
 
-data RonnDefinition = RonnDefinition
-  { name :: RonnPart
-  , description :: RonnLine
+data Definition = Definition
+  { name :: Part
+  , description :: Line
   -- ^ A line of nested description is required
-  , content :: Maybe [RonnContent]
+  , content :: Maybe [Content]
   -- ^ More content can be optionally nested
   }
 
-data RonnGroup
-  = RonnTitle ManRef [RonnPart]
-  | RonnHeader Text
-  | RonnLines [RonnLine]
+data Group
+  = Title ManRef [Part]
+  | Header Text
+  | Lines [Line]
 
-instance IsString RonnGroup where
-  fromString = RonnLines . pure . fromString
+instance IsString Group where
+  fromString = Lines . pure . fromString
 
-newtype RonnLine = RonnLine
-  { unwrap :: [RonnPart]
+newtype Line = Line
+  { unwrap :: [Part]
   }
 
-instance IsString RonnLine where
-  fromString = RonnLine . pure . fromString
+instance IsString Line where
+  fromString = Line . pure . fromString
 
-data RonnPart
-  = -- | 'RonnConcat' joins 'RonnPart's without automaticaly inserting a space
+data Part
+  = -- | 'Concat' joins 'Part's without automaticaly inserting a space
     --
     -- The following expressions are equivalent:
     --
-    -- - @'ronnLineToText' $ 'RonnLine' [p1, p2]@
-    -- - @'ronnLineToText' $ 'RonnLine' ['RonnConcat' [p1, " ", p2]]@
-    -- - @'ronnLineToText' $ 'RonnLine' [p1 <> " " <> p2]@
+    -- - @'ronnLineToText' $ 'Line' [p1, p2]@
+    -- - @'ronnLineToText' $ 'Line' ['Concat' [p1, " ", p2]]@
+    -- - @'ronnLineToText' $ 'Line' [p1 <> " " <> p2]@
     --
     -- Using the 'Semigroup' instance should be preferred, in case the AST
     -- changes in the future.
-    RonnConcat [RonnPart]
-  | RonnCode RonnPart
-  | RonnUserInput RonnPart
-  | RonnStrong RonnPart
-  | RonnVariable RonnPart
-  | RonnEphasis RonnPart
-  | RonnBrackets RonnPart
-  | RonnParens RonnPart
-  | RonnRef ManRef
-  | RonnRaw Text
-
-instance IsString RonnPart where
-  fromString = RonnRaw . pack
-
-instance Semigroup RonnPart where
-  RonnConcat as <> RonnConcat bs = RonnConcat $ as <> bs
-  RonnConcat as <> b = RonnConcat $ as <> [b]
-  a <> RonnConcat bs = RonnConcat $ a : bs
-  a <> b = RonnConcat [a, b]
-
-instance Monoid RonnPart where
-  mempty = RonnConcat []
+    Concat [Part]
+  | Code Part
+  | UserInput Part
+  | Strong Part
+  | Variable Part
+  | Ephasis Part
+  | Brackets Part
+  | Parens Part
+  | Ref ManRef
+  | Raw Text
 
-data ManRef = ManRef
-  { name :: Text
-  , section :: ManSection
-  }
+instance IsString Part where
+  fromString = Raw . pack
 
--- TODO: enum?
-newtype ManSection = ManSection Int
+instance Semigroup Part where
+  Concat as <> Concat bs = Concat $ as <> bs
+  Concat as <> b = Concat $ as <> [b]
+  a <> Concat bs = Concat $ a : bs
+  a <> b = Concat [a, b]
 
-manSectionNumber :: ManSection -> Int
-manSectionNumber (ManSection n) = n
+instance Monoid Part where
+  mempty = Concat []
diff --git a/src/Ronn/Argument.hs b/src/Ronn/Argument.hs
--- a/src/Ronn/Argument.hs
+++ b/src/Ronn/Argument.hs
@@ -21,7 +21,7 @@
 class HasArgument a where
   getArgument :: a -> Maybe String
 
-addArgument :: HasArgument a => Text -> a -> RonnPart -> RonnPart
+addArgument :: HasArgument a => Text -> a -> Part -> Part
 addArgument sep a p = case getArgument a of
   Nothing -> p
-  Just arg -> mconcat [p, RonnRaw sep, RonnVariable $ fromString arg]
+  Just arg -> mconcat [p, Raw sep, Variable $ fromString arg]
diff --git a/src/Ronn/Env.hs b/src/Ronn/Env.hs
deleted file mode 100644
--- a/src/Ronn/Env.hs
+++ /dev/null
@@ -1,50 +0,0 @@
--- |
---
--- Module      : Ronn.Env
--- Copyright   : (c) 2024 Patrick Brisbin
--- License     : AGPL-3
--- Maintainer  : pbrisbin@gmail.com
--- Stability   : experimental
--- Portability : POSIX
-module Ronn.Env
-  ( Env (..)
-  , envToDefinition
-  , environmentSection
-  ) where
-
-import Prelude
-
-import Data.List (intersperse)
-import Data.Maybe (fromMaybe)
-import Data.String (IsString (..))
-import Ronn.AST
-import Ronn.Argument
-
-data Env = Env
-  { vars :: [String]
-  , argument :: Maybe String
-  , default_ :: Maybe String
-  , help :: Maybe RonnLine
-  }
-
-instance HasArgument Env where
-  getArgument = (.argument)
-
-envToDefinition :: Env -> RonnDefinition
-envToDefinition env =
-  RonnDefinition
-    { name =
-        addArgument "=" env $
-          RonnConcat $
-            intersperse "|" $
-              map (RonnCode . fromString) env.vars
-    , description = fromMaybe (RonnLine []) env.help
-    , content = Nothing
-    }
-
-environmentSection :: [Env] -> RonnSection
-environmentSection envs =
-  RonnSection
-    { name = "ENVIRONMENT"
-    , content = [RonnDefinitions $ map envToDefinition envs]
-    }
diff --git a/src/Ronn/ManRef.hs b/src/Ronn/ManRef.hs
new file mode 100644
--- /dev/null
+++ b/src/Ronn/ManRef.hs
@@ -0,0 +1,42 @@
+-- |
+--
+-- Module      : Ronn.ManRef
+-- Copyright   : (c) 2024 Patrick Brisbin
+-- License     : AGPL-3
+-- Maintainer  : pbrisbin@gmail.com
+-- Stability   : experimental
+-- Portability : POSIX
+module Ronn.ManRef
+  ( ManRef (..)
+  , ManSection (..)
+  , manSectionNumber
+  )
+where
+
+import Prelude
+
+import Data.Ord
+import Data.Text
+
+data ManRef = ManRef
+  { name :: Text
+  , section :: ManSection
+  }
+  deriving stock (Eq, Show)
+
+instance Ord ManRef where
+  compare a b = comparing (.section) a b <> comparing (.name) a b
+
+data ManSection
+  = ManSection1
+  | ManSection2
+  | ManSection3
+  | ManSection4
+  | ManSection5
+  | ManSection6
+  | ManSection7
+  | ManSection8
+  deriving stock (Eq, Ord, Bounded, Enum, Show)
+
+manSectionNumber :: ManSection -> Int
+manSectionNumber = (+ 1) . fromEnum
diff --git a/src/Ronn/Opt.hs b/src/Ronn/Opt.hs
deleted file mode 100644
--- a/src/Ronn/Opt.hs
+++ /dev/null
@@ -1,105 +0,0 @@
--- |
---
--- Module      : Ronn.Opt
--- Copyright   : (c) 2024 Patrick Brisbin
--- License     : AGPL-3
--- Maintainer  : pbrisbin@gmail.com
--- Stability   : experimental
--- Portability : POSIX
-module Ronn.Opt
-  ( Opts (..)
-  , optsToDefinitions
-  , Opt (..)
-  , optToDefinition
-  , optionsSection
-  , synopsisSection
-  , synopsisLine
-  ) where
-
-import Prelude
-
-import Data.List (intersperse)
-import Data.Maybe (fromMaybe, isJust)
-import Data.String (IsString (..))
-import Ronn.AST
-import Ronn.Argument
-
-data Opts
-  = OptsOr Opts
-  | OptsAnd Opts
-  | OptsMany [Opts]
-  | OptsOne Opt
-
-optsToDefinitions :: Opts -> [RonnDefinition]
-optsToDefinitions = \case
-  OptsOr opts -> optsToDefinitions opts
-  OptsAnd opts -> optsToDefinitions opts
-  OptsMany opts -> concatMap optsToDefinitions opts
-  OptsOne opts -> [optToDefinition opts]
-
-data Opt = Opt
-  { shorts :: [Char]
-  , longs :: [String]
-  , argument :: Maybe String
-  , default_ :: Maybe String
-  , help :: Maybe RonnLine
-  }
-
-instance HasArgument Opt where
-  getArgument = (.argument)
-
-optToDefinition :: Opt -> RonnDefinition
-optToDefinition opt =
-  RonnDefinition
-    { name = mconcat $ intersperse ", " $ optParts opt
-    , description = fromMaybe (RonnLine []) opt.help
-    , content = Nothing
-    }
-
-optionsSection :: Opts -> RonnSection
-optionsSection opts =
-  RonnSection
-    { name = "OPTIONS"
-    , content = [RonnDefinitions $ optsToDefinitions opts]
-    }
-
-synopsisSection
-  :: String
-  -- ^ Program name
-  -> Opts
-  -> RonnSection
-synopsisSection name opts =
-  RonnSection
-    { name = "SYNOPSIS"
-    , content = [RonnGroups [RonnLines [synopsisLine name opts]]]
-    }
-
-synopsisLine :: String -> Opts -> RonnLine
-synopsisLine name = RonnLine . (RonnCode (fromString name) :) . go
- where
-  go :: Opts -> [RonnPart]
-  go = \case
-    OptsOr os -> [RonnBrackets $ mconcat $ intersperse " \\| " $ go os]
-    OptsAnd os -> [RonnParens $ mconcat $ intersperse " " $ go os]
-    OptsMany os -> concatMap go os
-    OptsOne opt -> map (bracketize opt) $ optParts opt
-
-  bracketize :: Opt -> RonnPart -> RonnPart
-  bracketize opt
-    | isJust opt.default_ = RonnBrackets
-    | otherwise = id
-
-optParts :: Opt -> [RonnPart]
-optParts opt
-  | null opt.shorts && null opt.longs
-  , Just arg <- opt.argument =
-      [RonnVariable $ fromString arg]
-  | otherwise =
-      map (addArgument " " opt . short) opt.shorts
-        <> map (addArgument "=" opt . long) opt.longs
- where
-  short :: Char -> RonnPart
-  short = RonnCode . fromString . ('-' :) . pure
-
-  long :: String -> RonnPart
-  long = RonnCode . fromString . ("--" <>)
diff --git a/src/Ronn/Render.hs b/src/Ronn/Render.hs
--- a/src/Ronn/Render.hs
+++ b/src/Ronn/Render.hs
@@ -8,6 +8,11 @@
 -- Portability : POSIX
 module Ronn.Render
   ( ronnToText
+
+    -- * Rendering sub-parts, mostly useful in tests
+  , ronnGroupToText
+  , ronnLineToText
+  , ronnPartToText
   ) where
 
 import Prelude
@@ -20,23 +25,23 @@
 ronnToText ronn =
   T.unlines $
     map ronnGroupToText $
-      RonnTitle ronn.name ronn.description
+      Title ronn.name ronn.description
         : concatMap ronnSectionToGroups ronn.sections
 
-ronnSectionToGroups :: RonnSection -> [RonnGroup]
+ronnSectionToGroups :: Section -> [Group]
 ronnSectionToGroups section =
-  RonnHeader section.name : concatMap (ronnContentToGroups 0) section.content
+  Header section.name : concatMap (ronnContentToGroups 0) section.content
 
-ronnContentToGroups :: Int -> RonnContent -> [RonnGroup]
+ronnContentToGroups :: Int -> Content -> [Group]
 ronnContentToGroups indentLevel = \case
-  RonnDefinitions defns ->
+  Definitions defns ->
     concatMap (ronnDefinitionToGroups $ indentLevel + 2) defns
-  RonnGroups gs -> map (indentRonnGroup indentLevel) gs
+  Groups gs -> map (indentRonnGroup indentLevel) gs
 
-ronnDefinitionToGroups :: Int -> RonnDefinition -> [RonnGroup]
+ronnDefinitionToGroups :: Int -> Definition -> [Group]
 ronnDefinitionToGroups indentLevel defn =
-  [ RonnLines
-      [ indentRonnLine indentLevel $ RonnLine ["* " <> defn.name <> ":"]
+  [ Lines
+      [ indentRonnLine indentLevel $ Line ["* " <> defn.name <> ":"]
       , indentRonnLine nextIndentLevel defn.description
       ]
   ]
@@ -45,38 +50,38 @@
   nested = maybe [] (concatMap $ ronnContentToGroups nextIndentLevel) defn.content
   nextIndentLevel = indentLevel + 2
 
-ronnGroupToText :: RonnGroup -> Text
+ronnGroupToText :: Group -> Text
 ronnGroupToText = T.unlines . map ronnLineToText . ronnGroupToLines
 
-ronnGroupToLines :: RonnGroup -> [RonnLine]
+ronnGroupToLines :: Group -> [Line]
 ronnGroupToLines = \case
-  RonnTitle ref description ->
+  Title ref description ->
     let nameLine = ronnNameLine ref description
     in  [ nameLine
-        , RonnLine [RonnRaw $ T.replicate (ronnLineLength nameLine) "="]
+        , Line [Raw $ T.replicate (ronnLineLength nameLine) "="]
         ]
-  RonnHeader name -> [RonnLine ["##", RonnRaw name]]
-  RonnLines ls -> ls
+  Header name -> [Line ["##", Raw name]]
+  Lines ls -> ls
 
-ronnNameLine :: ManRef -> [RonnPart] -> RonnLine
+ronnNameLine :: ManRef -> [Part] -> Line
 ronnNameLine ref =
-  RonnLine . (RonnRaw (manRefToText ref) :) . ("--" :)
+  Line . (Raw (manRefToText ref) :) . ("--" :)
 
-ronnLineToText :: RonnLine -> Text
+ronnLineToText :: Line -> Text
 ronnLineToText = T.unwords . map ronnPartToText . (.unwrap)
 
-ronnPartToText :: RonnPart -> Text
+ronnPartToText :: Part -> Text
 ronnPartToText = \case
-  RonnConcat xs -> mconcat $ map ronnPartToText xs
-  RonnCode x -> "`" <> ronnPartToText x <> "`"
-  RonnUserInput x -> "`" <> ronnPartToText x <> "`"
-  RonnStrong x -> "**" <> ronnPartToText x <> "**"
-  RonnVariable x -> "<" <> ronnPartToText x <> ">"
-  RonnEphasis x -> "_" <> ronnPartToText x <> "_"
-  RonnBrackets x -> "[" <> ronnPartToText x <> "]"
-  RonnParens x -> "(" <> ronnPartToText x <> ")"
-  RonnRef ref -> ronnPartToText $ RonnStrong $ RonnRaw $ manRefToText ref
-  RonnRaw x -> x
+  Concat xs -> mconcat $ map ronnPartToText xs
+  Code x -> "`" <> ronnPartToText x <> "`"
+  UserInput x -> "`" <> ronnPartToText x <> "`"
+  Strong x -> "**" <> ronnPartToText x <> "**"
+  Variable x -> "<" <> ronnPartToText x <> ">"
+  Ephasis x -> "_" <> ronnPartToText x <> "_"
+  Brackets x -> "[" <> ronnPartToText x <> "]"
+  Parens x -> "(" <> ronnPartToText x <> ")"
+  Ref ref -> ronnPartToText $ Strong $ Raw $ manRefToText ref
+  Raw x -> x
 
 manRefToText :: ManRef -> Text
 manRefToText ref =
@@ -85,19 +90,19 @@
     <> pack (show $ manSectionNumber ref.section)
     <> ")"
 
-ronnLineLength :: RonnLine -> Int
+ronnLineLength :: Line -> Int
 ronnLineLength = T.length . ronnLineToText
 
-indentRonnGroup :: Int -> RonnGroup -> RonnGroup
+indentRonnGroup :: Int -> Group -> Group
 indentRonnGroup indentLevel = \case
-  g@RonnTitle {} -> g
-  g@RonnHeader {} -> g
-  RonnLines ls -> RonnLines $ map (indentRonnLine indentLevel) ls
+  g@Title {} -> g
+  g@Header {} -> g
+  Lines ls -> Lines $ map (indentRonnLine indentLevel) ls
 
--- | Prepends the given number of spaces to the first 'RonnPart' of the line
-indentRonnLine :: Int -> RonnLine -> RonnLine
+-- | Prepends the given number of spaces to the first 'Part' of the line
+indentRonnLine :: Int -> Line -> Line
 indentRonnLine n = \case
-  RonnLine [] -> RonnLine []
-  RonnLine (p : ps) -> RonnLine $ (spaces <> p) : ps
+  Line [] -> Line []
+  Line (p : ps) -> Line $ (spaces <> p) : ps
  where
-  spaces = RonnRaw $ pack $ replicate n ' '
+  spaces = Raw $ pack $ replicate n ' '
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -1,1 +1,9 @@
+-- |
+--
+-- Module      : Main
+-- Copyright   : (c) 2024 Patrick Brisbin
+-- License     : AGPL-3
+-- Maintainer  : pbrisbin@gmail.com
+-- Stability   : experimental
+-- Portability : POSIX
 {-# OPTIONS_GHC -F -pgmF hspec-discover -Wno-missing-export-lists #-}
diff --git a/tests/Ronn/ManRefSpec.hs b/tests/Ronn/ManRefSpec.hs
new file mode 100644
--- /dev/null
+++ b/tests/Ronn/ManRefSpec.hs
@@ -0,0 +1,49 @@
+-- |
+--
+-- Module      : Ronn.ManRefSpec
+-- Copyright   : (c) 2024 Patrick Brisbin
+-- License     : AGPL-3
+-- Maintainer  : pbrisbin@gmail.com
+-- Stability   : experimental
+-- Portability : POSIX
+module Ronn.ManRefSpec
+  ( spec
+  ) where
+
+import Prelude
+
+import Data.List (sort)
+import Ronn.ManRef
+import Test.Hspec
+
+spec :: Spec
+spec = do
+  describe "ManRef" $ do
+    describe "Ord" $ do
+      it "sorts section then name" $ do
+        let
+          unsorted =
+            [ ManRef "groff_man" ManSection7
+            , ManRef "man" ManSection1
+            , ManRef "man2html" ManSection1
+            , ManRef "mdoc" ManSection7
+            , ManRef "groff" ManSection7
+            , ManRef "man" ManSection7
+            , ManRef "attributes" ManSection7
+            ]
+          sorted =
+            [ ManRef "man" ManSection1
+            , ManRef "man2html" ManSection1
+            , ManRef "attributes" ManSection7
+            , ManRef "groff" ManSection7
+            , ManRef "groff_man" ManSection7
+            , ManRef "man" ManSection7
+            , ManRef "mdoc" ManSection7
+            ]
+
+        sort unsorted `shouldBe` sorted
+
+  describe "ManSection" $ do
+    describe "manSectionNumber" $ do
+      it "can be converted to numbers 1 though 8" $ do
+        map manSectionNumber [minBound .. maxBound] `shouldBe` [1 .. 8]
diff --git a/tests/Ronn/RenderSpec.hs b/tests/Ronn/RenderSpec.hs
--- a/tests/Ronn/RenderSpec.hs
+++ b/tests/Ronn/RenderSpec.hs
@@ -1,5 +1,11 @@
-{-# OPTIONS_GHC -Wno-ambiguous-fields #-}
-
+-- |
+--
+-- Module      : Ronn.RenderSpec
+-- Copyright   : (c) 2024 Patrick Brisbin
+-- License     : AGPL-3
+-- Maintainer  : pbrisbin@gmail.com
+-- Stability   : experimental
+-- Portability : POSIX
 module Ronn.RenderSpec
   ( spec
   ) where
@@ -7,183 +13,153 @@
 import Prelude
 
 import Data.List (intersperse)
-import Data.Text qualified as T
-import Ronn.AST
-import Ronn.Env
-import Ronn.Opt
-import Ronn.Render
+import Data.Text (Text, unpack)
+import Data.Text.IO qualified as T
+import Ronn
+import System.FilePath ((</>))
 import Test.Hspec
+import Test.Hspec.Golden
 
 spec :: Spec
 spec = do
   describe "ronnToText" $ do
-    specify "a complete example" $ do
-      let
-        opts =
-          OptsMany
-            [ OptsOne $
-                Opt
-                  { shorts = ['h']
-                  , longs = ["help"]
-                  , argument = Nothing
-                  , default_ = Just ""
-                  , help = Just "Display this help"
-                  }
-            , OptsOr $
-                OptsMany
-                  [ OptsOne $
-                      Opt
-                        { shorts = []
-                        , longs = ["debug"]
-                        , argument = Nothing
-                        , default_ = Nothing
-                        , help = Just "Enable debug"
-                        }
-                  , OptsOne $
-                      Opt
-                        { shorts = []
-                        , longs = ["trace"]
-                        , argument = Nothing
-                        , default_ = Nothing
-                        , help = Just "Enable trace"
-                        }
-                  ]
-            , OptsOne $
-                Opt
-                  { shorts = ['o']
-                  , longs = ["output"]
-                  , argument = Just "FILE"
-                  , default_ = Just "-"
-                  , help = Just $ RonnLine ["Output to", RonnVariable "FILE"]
+    specify "a complete example" $
+      ronnGolden $
+        Ronn
+          { name = ManRef "ronn" ManSection1
+          , description = ["example ronn man-page"]
+          , sections =
+              [ Section
+                  { name = "SYNOPSIS"
+                  , content =
+                      [ Groups
+                          [ Lines
+                              [ Line
+                                  [ Code "ronn"
+                                  , Brackets $ Code "-h"
+                                  , Brackets $ Code "--help"
+                                  , Brackets $ mconcat [Code "--debug", "|", Code "--trace"]
+                                  , Brackets $ mconcat [Code "-o", " ", Variable "FILE"]
+                                  , Brackets $ mconcat [Code "--output", "=", Variable "FILE"]
+                                  , Variable "INPUT"
+                                  ]
+                              ]
+                          ]
+                      ]
                   }
-            , OptsOne $
-                Opt
-                  { shorts = []
-                  , longs = []
-                  , argument = Just "INPUT"
-                  , default_ = Nothing
-                  , help = Just "Source input"
+              , Section
+                  { name = "DESCRIPTION"
+                  , content =
+                      [ Groups
+                          [ Lines
+                              [ Line -- test unwords-like behavior
+                                  [ "This is an"
+                                  , "example man-page to show"
+                                  , "how rendering the AST looks."
+                                  ]
+                              ]
+                          ]
+                      ]
                   }
-            ]
-
-        ronn =
-          Ronn
-            { name = ManRef "ronn" $ ManSection 1
-            , description = ["example ronn man-page"]
-            , sections =
-                [ synopsisSection "ronn" opts
-                , RonnSection
-                    { name = "DESCRIPTION"
-                    , content =
-                        [ RonnGroups
-                            [ RonnLines
-                                [ RonnLine -- test unwords-like behavior
-                                    [ "This is an"
-                                    , "example man-page to show"
-                                    , "how rendering the AST looks."
+              , Section
+                  { name = "OPTIONS"
+                  , content =
+                      [ Definitions
+                          [ Definition
+                              { name =
+                                  mconcat
+                                    [ Code "-h"
+                                    , ", "
+                                    , Code "--help"
                                     ]
-                                ]
-                            ]
-                        ]
-                    }
-                , optionsSection opts
-                , RonnSection
-                    { name = "ENVIRONMENT"
-                    , content =
-                        [ RonnDefinitions
-                            [ ( envToDefinition $
-                                  Env
-                                    { vars = ["HOME"]
-                                    , argument = Nothing
-                                    , default_ = Nothing
-                                    , help = Just "User's HOME directory"
-                                    }
-                              )
-                                { content =
-                                    Just
-                                      [ "Some further details:"
-                                      , RonnDefinitions
-                                          [ RonnDefinition
-                                              { name = "foo"
-                                              , description = "The foo"
-                                              , content = Nothing
-                                              }
-                                          , RonnDefinition
-                                              { name = "bar"
-                                              , description = "The bar"
-                                              , content = Nothing
-                                              }
-                                          ]
-                                      ]
-                                }
-                            ]
-                        ]
-                    }
-                , RonnSection
-                    { name = "SEE ALSO"
-                    , content =
-                        [ RonnGroups
-                            [ RonnLines
-                                [ RonnLine
-                                    [ RonnConcat $
-                                        intersperse
-                                          (RonnRaw ", ")
-                                          [ RonnRef $ ManRef "markdown" $ ManSection 7
-                                          , RonnRef $ ManRef "roff" $ ManSection 7
-                                          ]
+                              , description = "Display this help"
+                              , content = Nothing
+                              }
+                          , Definition
+                              { name = Code "--debug"
+                              , description = "Enable debug"
+                              , content = Nothing
+                              }
+                          , Definition
+                              { name = Code "--trace"
+                              , description = "Enable trace"
+                              , content = Nothing
+                              }
+                          , Definition
+                              { name =
+                                  mconcat
+                                    [ Code "-o"
+                                    , ", "
+                                    , Code "--output"
+                                    , "="
+                                    , Variable "FILE"
                                     ]
-                                ]
-                            ]
-                        ]
-                    }
-                ]
-            }
+                              , description = Line ["Output to", Variable "FILE"]
+                              , content = Nothing
+                              }
+                          , Definition
+                              { name = Variable "INPUT"
+                              , description = "Source input"
+                              , content = Nothing
+                              }
+                          ]
+                      ]
+                  }
+              , Section
+                  { name = "ENVIRONMENT"
+                  , content =
+                      [ Definitions
+                          [ Definition
+                              { name = Code "HOME"
+                              , description = "User's HOME directory"
+                              , content =
+                                  Just
+                                    [ "Some further details:"
+                                    , Definitions
+                                        [ Definition
+                                            { name = "foo"
+                                            , description = "The foo"
+                                            , content = Nothing
+                                            }
+                                        , Definition
+                                            { name = "bar"
+                                            , description = "The bar"
+                                            , content = Nothing
+                                            }
+                                        ]
+                                    ]
+                              }
+                          ]
+                      ]
+                  }
+              , Section
+                  { name = "SEE ALSO"
+                  , content =
+                      [ Groups
+                          [ Lines
+                              [ Line
+                                  [ mconcat $
+                                      intersperse
+                                        (Raw ", ")
+                                        [ Ref $ ManRef "markdown" ManSection7
+                                        , Ref $ ManRef "roff" ManSection7
+                                        ]
+                                  ]
+                              ]
+                          ]
+                      ]
+                  }
+              ]
+          }
 
-      ronnToText ronn
-        `shouldBe` T.unlines
-          [ "ronn(1) -- example ronn man-page"
-          , "================================"
-          , ""
-          , "## SYNOPSIS"
-          , ""
-          , "`ronn` [`-h`] [`--help`] [`--debug` \\| `--trace`] [`-o` <FILE>] [`--output`=<FILE>] <INPUT>"
-          , ""
-          , "## DESCRIPTION"
-          , ""
-          , "This is an example man-page to show how rendering the AST looks."
-          , ""
-          , "## OPTIONS"
-          , ""
-          , "  * `-h`, `--help`:"
-          , "    Display this help"
-          , ""
-          , "  * `--debug`:"
-          , "    Enable debug"
-          , ""
-          , "  * `--trace`:"
-          , "    Enable trace"
-          , ""
-          , "  * `-o` <FILE>, `--output`=<FILE>:"
-          , "    Output to <FILE>"
-          , ""
-          , "  * <INPUT>:"
-          , "    Source input"
-          , ""
-          , "## ENVIRONMENT"
-          , ""
-          , "  * `HOME`:"
-          , "    User's HOME directory"
-          , ""
-          , "    Some further details:"
-          , ""
-          , "      * foo:"
-          , "        The foo"
-          , ""
-          , "      * bar:"
-          , "        The bar"
-          , ""
-          , "## SEE ALSO"
-          , ""
-          , "**markdown(7)**, **roff(7)**"
-          , ""
-          ]
+ronnGolden :: Ronn -> Golden Text
+ronnGolden ronn =
+  Golden
+    { output = ronnToText ronn
+    , encodePretty = unpack
+    , writeToFile = T.writeFile
+    , readFromFile = T.readFile
+    , goldenFile = "../doc" </> ronnFilePath ronn
+    , actualFile = Nothing
+    , failFirstTime = False
+    }
