diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
 ## [_Unreleased_](https://github.com/pbrisbin/ronn/compare/ronn-optparse-applicative-v1.0.1.0...main)
 
-## [v1.0.1.0](https://github.com/pbrisbin/ronn/tree/ronn-optparse-applicative-v1.0.1.0)
+## [v1.0.2.0](https://github.com/pbrisbin/ronn/compare/ronn-optparse-applicative-v1.0.1.0...ronn-optparse-applicative-v1.0.2.0)
+
+- Implement `COMMANDS` section generation
+
+## [v1.0.1.0](https://github.com/pbrisbin/ronn/compare/ronn-optparse-applicative-v1.0.0.0...ronn-optparse-applicative-v1.0.1.0)
 
 - Add `HasSections` instance
 
diff --git a/ronn-optparse-applicative.cabal b/ronn-optparse-applicative.cabal
--- a/ronn-optparse-applicative.cabal
+++ b/ronn-optparse-applicative.cabal
@@ -1,6 +1,6 @@
 cabal-version:   1.18
 name:            ronn-optparse-applicative
-version:         1.0.1.0
+version:         1.0.2.0
 license:         AGPL-3
 maintainer:      Pat Brisbin
 homepage:        https://github.com/pbrisbin/ronn#readme
@@ -39,7 +39,7 @@
     build-depends:
         base >=4.16.4.0 && <5,
         optparse-applicative >=0.17.1.0,
-        ronn >=1.1.1.0,
+        ronn >=1.1.2.0,
         text >=1.2.5.0
 
     if impl(ghc >=9.8)
diff --git a/src/Ronn/Options/Applicative.hs b/src/Ronn/Options/Applicative.hs
--- a/src/Ronn/Options/Applicative.hs
+++ b/src/Ronn/Options/Applicative.hs
@@ -16,7 +16,9 @@
 import Prelude
 
 import Control.Monad (void)
+import Data.Foldable (toList)
 import Data.List (intersperse, sortBy)
+import Data.List.NonEmpty (nonEmpty)
 import Data.String (IsString (..))
 import Data.Text (Text)
 import Options.Applicative (Parser)
@@ -30,13 +32,15 @@
   , OptReader (..)
   , OptTree (..)
   , Option (..)
+  , ParserInfo (..)
   )
 import Ronn (HasSections (..))
 import Ronn.AST
 
 instance HasSections Parser where
   getSynopsis = Just . optSynopsis
-  getOptDefinitions = Just . optDefinitions
+  getOptDefinitions = fmap toList . nonEmpty . optDefinitions
+  getCmdDefinitions = fmap toList . nonEmpty . cmdDefinitions
 
 optSynopsis :: Parser a -> [Part]
 optSynopsis = go False . treeMapParser (const void)
@@ -69,36 +73,54 @@
       case propShowDefault $ optProps o of
         Nothing -> Variable $ fromString $ propMetaVar $ optProps o
         Just {} -> Brackets $ fromString $ propMetaVar $ optProps o
-    CmdReader {} -> "" -- TODO
+    CmdReader {} -> Variable $ fromString $ propMetaVar $ optProps o
   bracketize = case propShowDefault $ optProps o of
     Nothing -> id
     Just {} -> Brackets
 
 optDefinitions :: Parser a -> [Definition]
-optDefinitions = mapParser optDefinition
+optDefinitions = concat . mapParser optDefinition
 
-optDefinition :: a -> Option x -> Definition
-optDefinition _ o =
-  Definition
-    { name = case optMain o of
-        OptReader names _ _ ->
-          let mv = propMetaVar $ optProps o
-          in  Concat $ intersperse ", " $ renderNames (Just mv) names
-        FlagReader names _ ->
-          Concat $ intersperse ", " $ renderNames Nothing names
-        ArgReader {} -> Code $ fromString $ propMetaVar $ optProps o
-        CmdReader {} -> undefined -- TODO
-    , description =
-        let
-          help = Raw (docToText $ propHelp $ optProps o)
-          suffix =
-            maybe [] (pure . Parens . ("default " <>) . fromString) $
-              propShowDefault $
-                optProps o
-        in
-          Line $ help : suffix
-    , content = Nothing
-    }
+cmdDefinitions :: Parser a -> [Definition]
+cmdDefinitions = concat . mapParser cmdDefinition
+
+optDefinition :: a -> Option x -> [Definition]
+optDefinition _ o = case optMain o of
+  OptReader names _ _ ->
+    let mv = propMetaVar $ optProps o
+    in  [basicDefinition $ Concat $ intersperse ", " $ renderNames (Just mv) names]
+  FlagReader names _ ->
+    [basicDefinition $ Concat $ intersperse ", " $ renderNames Nothing names]
+  ArgReader {} ->
+    [basicDefinition $ Code $ fromString $ propMetaVar $ optProps o]
+  CmdReader {} -> []
+ where
+  basicDefinition name = Definition {name, description = basicDescription, content = Nothing}
+  basicDescription =
+    let
+      help = Raw (docToText $ propHelp $ optProps o)
+      suffix =
+        maybe [] (pure . Parens . ("default " <>) . fromString) $
+          propShowDefault $
+            optProps o
+    in
+      Line $ help : suffix
+
+cmdDefinition :: a -> Option x -> [Definition]
+cmdDefinition _ o = case optMain o of
+  OptReader {} -> []
+  FlagReader {} -> []
+  ArgReader {} -> []
+  CmdReader _ cmds ->
+    map
+      ( \(cmd, info) ->
+          Definition
+            { name = Code $ fromString cmd
+            , description = Line $ pure $ Raw $ docToText $ infoProgDesc info
+            , content = Nothing
+            }
+      )
+      $ reverse cmds
 
 docToText :: Chunk Doc -> Text
 docToText =
diff --git a/tests/Ronn/Options/ApplicativeSpec.hs b/tests/Ronn/Options/ApplicativeSpec.hs
--- a/tests/Ronn/Options/ApplicativeSpec.hs
+++ b/tests/Ronn/Options/ApplicativeSpec.hs
@@ -21,7 +21,7 @@
 spec = do
   specify "complete example" $
     ronnGolden "optparse-applicative" $
-      (,,)
+      (,,,)
         <$> optional (switch (long "debug" <> help "Enable debug"))
         <*> option
           (str @String)
@@ -35,3 +35,19 @@
               ]
           )
         <*> argument (str @String) (help "Input file" <> metavar "INPUT")
+        <*> subparser
+          ( command
+              "serve"
+              ( info
+                  (pure ())
+                  (progDesc "Run the server")
+              )
+              <> command
+                "build"
+                ( info
+                    (pure ())
+                    (progDesc "Build the project")
+                )
+              <> metavar "COMMAND"
+              <> help "Command to run"
+          )
