diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,22 @@
 # Changelog for harg
 
+## 0.5.0.0 [2021.03.02]
+
+Library updates:
+
+- Add support for ghc >= 8.8 by updating `barbies` and `higgledy`. This means
+  that **support is dropped** for ghc <= 8.2 (because of `barbies`)
+- Expose `HasX` classes from `Construct.hs`
+- Because of changes in `barbies`, `ApplicativeB` is exposed from `Options.Harg`
+  instead of `ProductB`
+
+CI & development updates:
+
+- Update nix sources for using cached ghc v8.8.4 and dependencies
+- Add stack configuration for ghc v8.8.4 (lts-16.31 resolver)
+- Update github actions workflow to build both v8.8.4 and v8.6.5 with cabal and
+  stack
+
 ## 0.4.2.1 [2020.08.01]
 
 Only cosmetic and functional changes, no library changes:
diff --git a/docs/docs.lhs b/docs/docs.lhs
--- a/docs/docs.lhs
+++ b/docs/docs.lhs
@@ -24,25 +24,22 @@
 extensions and add some imports:
 
 ``` haskell
-{-# LANGUAGE DataKinds          #-}
-{-# LANGUAGE DeriveAnyClass     #-}
-{-# LANGUAGE DeriveGeneric      #-}
-{-# LANGUAGE FlexibleInstances  #-}
-{-# LANGUAGE GADTs              #-}
-{-# LANGUAGE KindSignatures     #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE StandaloneDeriving #-}
-{-# LANGUAGE TypeApplications   #-}
-{-# LANGUAGE TypeOperators      #-}
-
-import           Data.Functor.Identity (Identity (..))
-import           Data.Kind             (Type)
-import           GHC.Generics          (Generic)
-
-import qualified Data.Barbie           as B
-import           Data.Aeson            (FromJSON)
-import           Data.Generic.HKD      (HKD, build, construct)
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeOperators #-}
 
-import           Options.Harg
+import qualified Barbies as B
+import Data.Aeson (FromJSON)
+import Data.Functor.Identity (Identity (..))
+import Data.Kind (Type)
+import GHC.Generics (Generic)
+import Options.Harg
 
 main :: IO ()
 main = putStrLn "this is a literate haskell file"
@@ -54,13 +51,12 @@
 with no levels of nesting:
 
 ``` haskell
-data FlatConfig
-  = FlatConfig
-      { _fcDbHost :: String
-      , _fcDbPort :: Int
-      , _fcDir    :: String
-      , _fcLog    :: Bool  -- whether to log or not
-      }
+data FlatConfig = FlatConfig
+  { _fcDbHost :: String,
+    _fcDbPort :: Int,
+    _fcDir :: String,
+    _fcLog :: Bool -- whether to log or not
+  }
   deriving (Show, Generic)
 ```
 
@@ -71,36 +67,39 @@
 
 ``` haskell
 dbHostOpt :: Opt String
-dbHostOpt
-  = option strParser
-      ( long "host"
-      . short 'h'
-      . metavar "DB_HOST"
-      . help "The database host"
-      )
+dbHostOpt =
+  option
+    strParser
+    ( long "host"
+        . short 'h'
+        . metavar "DB_HOST"
+        . help "The database host"
+    )
 
 dbPortOpt :: Opt Int
-dbPortOpt
-  = option readParser
-      ( long "port"
-      . help "The database port"
-      . envVar "DB_PORT"
-      . defaultVal 5432
-      )
+dbPortOpt =
+  option
+    readParser
+    ( long "port"
+        . help "The database port"
+        . envVar "DB_PORT"
+        . defaultVal 5432
+    )
 
 dirOpt :: Opt String
-dirOpt
-  = argument strParser
-      ( help "Some directory"
-      . defaultVal "/home/user/something"
-      )
+dirOpt =
+  argument
+    strParser
+    ( help "Some directory"
+        . defaultVal "/home/user/something"
+    )
 
 logOpt :: Opt Bool
-logOpt
-  = switch
-      ( long "log"
-      . help "Whether to log or not"
-      )
+logOpt =
+  switch
+    ( long "log"
+        . help "Whether to log or not"
+    )
 ```
 
 Here, we use `option` to define a command line argument that expects a value
@@ -130,8 +129,8 @@
 
 ``` haskell
 dbPortOpt' :: Opt Port
-dbPortOpt'
-  = Port <$> dbPortOpt
+dbPortOpt' =
+  Port <$> dbPortOpt
 ```
 
 Of course, any user-defined function works as well. In addition, to use a
@@ -147,11 +146,12 @@
 
 ``` hs
 someOpt :: Opt (Maybe Int)
-someOpt
-  = option readParser
-      ( long "something"
-      . optional
-      )
+someOpt =
+  option
+    readParser
+    ( long "something"
+        . optional
+    )
 ```
 
 Note that `optional` can't be used with `defaultVal`. Using them together raises
@@ -166,14 +166,13 @@
 `FlatConfig` looks like this:
 
 ``` haskell
-data FlatConfigB f
-  = FlatConfigB
-      { _fcDbHostB :: f String
-      , _fcDbPortB :: f Int
-      , _fcDirB    :: f String
-      , _fcLogB    :: f Bool
-      }
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+data FlatConfigB f = FlatConfigB
+  { _fcDbHostB :: f String,
+    _fcDbPortB :: f Int,
+    _fcDirB :: f String,
+    _fcLogB :: f Bool
+  }
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 ```
 
 I also derived some required instances that come from the `barbies` package.
@@ -186,8 +185,8 @@
 
 ``` haskell
 flatConfigOpt1 :: FlatConfigB Opt
-flatConfigOpt1
-  = FlatConfigB dbHostOpt dbPortOpt dirOpt logOpt
+flatConfigOpt1 =
+  FlatConfigB dbHostOpt dbPortOpt dirOpt logOpt
 ```
 
 Because `dbHostOpt`, `dbPortOpt` and `logOpt` all have type `Opt <actual type>`,
@@ -199,12 +198,13 @@
 getFlatConfig1 :: IO ()
 getFlatConfig1 = do
   FlatConfigB host port dir log <- execOptDef flatConfigOpt1
-  print $ runIdentity $
-    FlatConfig
-    <$> host
-    <*> port
-    <*> dir
-    <*> log
+  print $
+    runIdentity $
+      FlatConfig
+        <$> host
+        <*> port
+        <*> dir
+        <*> log
 ```
 
 `execOpt` returns an `Identity x` where `x` is the type of the options we are
@@ -225,24 +225,25 @@
 in `Options.Harg.Het.Prod` and is called `:*` (the `*` stands for product). This
 type stores barbie-like types and also keeps the `f` handy: `data (a :* b) f = a
 f :* b f`. This is also easily made an instance of `Generic`, `FunctorB`,
-`TraversableB` and `ProductB`. With all that, let's rewrite the options value
-and the function to get the configuration:
+`TraversableB` and `ApplicativeB`. With all that, let's rewrite the options
+value and the function to get the configuration:
 
 ``` haskell
-flatConfigOpt2
-  :: (Single String :* Single Int :* Single String :* Single Bool) Opt
-flatConfigOpt2
-  = single dbHostOpt :* single dbPortOpt :* single dirOpt :* single logOpt
+flatConfigOpt2 ::
+  (Single String :* Single Int :* Single String :* Single Bool) Opt
+flatConfigOpt2 =
+  single dbHostOpt :* single dbPortOpt :* single dirOpt :* single logOpt
 
 getFlatConfig2 :: IO ()
 getFlatConfig2 = do
   host :* port :* dir :* log <- execOptDef flatConfigOpt2
-  print $ runIdentity $
-    FlatConfig
-    <$> getSingle host
-    <*> getSingle port
-    <*> getSingle dir
-    <*> getSingle log
+  print $
+    runIdentity $
+      FlatConfig
+        <$> getSingle host
+        <*> getSingle port
+        <*> getSingle dir
+        <*> getSingle log
 ```
 
 This looks aufully similar to the previous version, but without having to write
@@ -257,10 +258,10 @@
 definitions look more similar to datatype definitions:
 
 ``` haskell
-type FlatConfigOpt2
-  =  Single String
-  :* Single Int
-  :* Single Bool
+type FlatConfigOpt2 =
+  Single String
+    :* Single Int
+    :* Single Bool
 ```
 
 In addition, `single` is used to wrap an `f a` into a `Single a f`, and
@@ -274,8 +275,8 @@
 
 ``` haskell
 flatConfigOpt3 :: HKD FlatConfig Opt
-flatConfigOpt3
-  = build @FlatConfig dbHostOpt dbPortOpt dirOpt logOpt
+flatConfigOpt3 =
+  build @FlatConfig dbHostOpt dbPortOpt dirOpt logOpt
 
 getFlatConfig3 :: IO ()
 getFlatConfig3 = do
@@ -299,30 +300,27 @@
 Let's say now that we have these two datatypes:
 
 ``` haskell
-data DbConfig
-  = DbConfig
-      { _dcHost :: String
-      , _dcPort :: Int
-      }
+data DbConfig = DbConfig
+  { _dcHost :: String,
+    _dcPort :: Int
+  }
   deriving (Show, Generic)
 
-data ServiceConfig
-  = ServiceConfig
-      { _scPort :: Int
-      , _scLog  :: Bool
-      }
+data ServiceConfig = ServiceConfig
+  { _scPort :: Int,
+    _scLog :: Bool
+  }
   deriving (Show, Generic)
 ```
 
 And the datatype to be configured is this:
 
 ``` haskell
-data Config
-  = Config
-      { _cDb      :: DbConfig
-      , _cService :: ServiceConfig
-      , _cDir     :: String
-      }
+data Config = Config
+  { _cDb :: DbConfig,
+    _cService :: ServiceConfig,
+    _cDir :: String
+  }
   deriving (Show, Generic)
 ```
 
@@ -330,12 +328,13 @@
 
 ``` haskell
 portOpt :: Opt Int
-portOpt
-  = option readParser
-      ( long "port"
-      . help "The service port"
-      . defaultVal 8080
-      )
+portOpt =
+  option
+    readParser
+    ( long "port"
+        . help "The service port"
+        . defaultVal 8080
+    )
 ```
 
 Again, there are several ways to configure these options.
@@ -345,27 +344,24 @@
 Since we now have 3 types, there's a bit more boilerplate to write:
 
 ``` haskell
-data ConfigB f
-  = ConfigB
-      { _cDbB      :: DbConfigB f
-      , _cServiceB :: ServiceConfigB f
-      , _cDirB     :: f String
-      }
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+data ConfigB f = ConfigB
+  { _cDbB :: DbConfigB f,
+    _cServiceB :: ServiceConfigB f,
+    _cDirB :: f String
+  }
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 
-data DbConfigB f
-  = DbConfigB
-      { _dcHostB :: f String
-      , _dcPortB :: f Int
-      }
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+data DbConfigB f = DbConfigB
+  { _dcHostB :: f String,
+    _dcPortB :: f Int
+  }
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 
-data ServiceConfigB f
-  = ServiceConfigB
-      { _scPortB :: f Int
-      , _scLogB  :: f Bool
-      }
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+data ServiceConfigB f = ServiceConfigB
+  { _scPortB :: f Int,
+    _scLogB :: f Bool
+  }
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 ```
 
 To define the option parser, we need option parsers for every type inside it.
@@ -374,16 +370,16 @@
 
 ``` haskell
 configOpt1 :: ConfigB Opt
-configOpt1
-  = ConfigB dbOpt serviceOpt dirOpt
+configOpt1 =
+  ConfigB dbOpt serviceOpt dirOpt
 
 dbOpt :: DbConfigB Opt
-dbOpt
-  = DbConfigB dbHostOpt dbPortOpt
+dbOpt =
+  DbConfigB dbHostOpt dbPortOpt
 
 serviceOpt :: ServiceConfigB Opt
-serviceOpt
-  = ServiceConfigB portOpt logOpt
+serviceOpt =
+  ServiceConfigB portOpt logOpt
 ```
 
 And to run the parser:
@@ -393,14 +389,14 @@
 getConfig1 = do
   ConfigB (DbConfigB dbHost dbPort) (ServiceConfigB port log) dir <-
     execOptDef configOpt1
-  let
-    db      = DbConfig <$> dbHost <*> dbPort
-    service = ServiceConfig <$> port <*> log
-  print $ runIdentity $
-    Config
-    <$> db
-    <*> service
-    <*> dir
+  let db = DbConfig <$> dbHost <*> dbPort
+      service = ServiceConfig <$> port <*> log
+  print $
+    runIdentity $
+      Config
+        <$> db
+        <*> service
+        <*> dir
 ```
 
 ### 2. Using `higgledy`
@@ -411,25 +407,24 @@
 of defining `barbie` types for the nested datatypes:
 
 ``` haskell
-data ConfigH f
-  = ConfigH
-      { _cDbH      :: HKD DbConfig f
-      , _cServiceH :: HKD ServiceConfig f
-      , _cDirH     :: f String
-      }
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+data ConfigH f = ConfigH
+  { _cDbH :: HKD DbConfig f,
+    _cServiceH :: HKD ServiceConfig f,
+    _cDirH :: f String
+  }
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 
 configOpt2 :: ConfigH Opt
-configOpt2
-  = ConfigH dbOptH serviceOptH dirOpt
+configOpt2 =
+  ConfigH dbOptH serviceOptH dirOpt
 
 dbOptH :: HKD DbConfig Opt
-dbOptH
-  = build @DbConfig dbHostOpt dbPortOpt
+dbOptH =
+  build @DbConfig dbHostOpt dbPortOpt
 
 serviceOptH :: HKD ServiceConfig Opt
-serviceOptH
-  = build @ServiceConfig portOpt logOpt
+serviceOptH =
+  build @ServiceConfig portOpt logOpt
 ```
 
 And to run the parser:
@@ -438,11 +433,12 @@
 getConfig2 :: IO ()
 getConfig2 = do
   ConfigH db service dir <- execOptDef configOpt2
-  print $ runIdentity $
-    Config
-    <$> construct db
-    <*> construct service
-    <*> dir
+  print $
+    runIdentity $
+      Config
+        <$> construct db
+        <*> construct service
+        <*> dir
 ```
 
 ### 2. Using products
@@ -453,23 +449,24 @@
 a new datatype:
 
 ``` haskell
-type ConfigP
-  =  HKD DbConfig
-  :* HKD ServiceConfig
-  :* Single String
+type ConfigP =
+  HKD DbConfig
+    :* HKD ServiceConfig
+    :* Single String
 
 configOpt3 :: ConfigP Opt
-configOpt3
-  = dbOptH :* serviceOptH :* single dirOpt
+configOpt3 =
+  dbOptH :* serviceOptH :* single dirOpt
 
 getConfig3 :: IO ()
 getConfig3 = do
   db :* service :* dir <- execOptDef configOpt3
-  print $ runIdentity $
-    Config
-    <$> construct db
-    <*> construct service
-    <*> getSingle dir
+  print $
+    runIdentity $
+      Config
+        <$> construct db
+        <*> construct service
+        <*> getSingle dir
 ```
 
 And, to make things look more orthogonal, `harg` defines a type called `Nested`,
@@ -485,28 +482,29 @@
 This means that the previous code block might as well be:
 
 ``` haskell
-type ConfigP'
-  =  Nested DbConfig
-  :* Nested ServiceConfig
-  :* Single String
+type ConfigP' =
+  Nested DbConfig
+    :* Nested ServiceConfig
+    :* Single String
 
 configOpt4 :: ConfigP' Opt
-configOpt4
-  = dbOptN :* serviceOptN :* single dirOpt
+configOpt4 =
+  dbOptN :* serviceOptN :* single dirOpt
   where
-    dbOptN
-      = nested @DbConfig dbHostOpt dbPortOpt
-    serviceOptN
-      = nested @ServiceConfig portOpt logOpt
+    dbOptN =
+      nested @DbConfig dbHostOpt dbPortOpt
+    serviceOptN =
+      nested @ServiceConfig portOpt logOpt
 
 getConfig4 :: IO ()
 getConfig4 = do
   db :* service :* dir <- execOptDef configOpt4
-  print $ runIdentity $
-    Config
-    <$> getNested db
-    <*> getNested service
-    <*> getSingle dir
+  print $
+    runIdentity $
+      Config
+        <$> getNested db
+        <*> getNested service
+        <*> getSingle dir
 ```
 
 Pretty cool.
@@ -542,8 +540,8 @@
 x = There (Here True)
 
 run :: Variant '[Int, Bool, Char] -> Maybe Bool
-run (Here _)                 = Nothing
-run (There (Here b))         = Just b
+run (Here _) = Nothing
+run (There (Here b)) = Just b
 run (There (There (Here _))) = Nothing
 
 -- > run x
@@ -553,7 +551,7 @@
 `harg` defines another kind of variant called `VariantF`:
 
 ``` hs
-data VariantF (xs :: [(Type -> Type) -> Type]) (f :: Type -> Type) where
+data VariantF (xs :: [(Type -> Type) -> Type]) (f :: Type -> Type)
 ```
 
 to hold a type-level list of `barbie` types and the `f` to wrap every type with.
@@ -565,51 +563,52 @@
 is the configuration when the command is `test`:
 
 ``` haskell
-data TestConfig
-  = TestConfig
-      { _tcFoo :: String
-      , _tcBar :: Int
-      }
-  deriving Show
+data TestConfig = TestConfig
+  { _tcFoo :: String,
+    _tcBar :: Int
+  }
+  deriving (Show)
 
 fooOpt :: Opt String
-fooOpt
-  = option strParser
-      ( short 'f'
-      . help "Something foo"
-      . defaultVal "this is the default foo"
-      )
+fooOpt =
+  option
+    strParser
+    ( short 'f'
+        . help "Something foo"
+        . defaultVal "this is the default foo"
+    )
 
 barOpt :: Opt Int
-barOpt
-  = option readParser
-      ( short 'b'
-      . help "Something bar"
-      . defaultVal 42
-      )
+barOpt =
+  option
+    readParser
+    ( short 'b'
+        . help "Something bar"
+        . defaultVal 42
+    )
 
-type TestConfigP
-  = Single String :* Single Int
+type TestConfigP =
+  Single String :* Single Int
 
 testConfigOpt :: TestConfigP Opt
-testConfigOpt
-  = single fooOpt :* single barOpt
+testConfigOpt =
+  single fooOpt :* single barOpt
 ```
 
 The subcommand type looks like this:
 
 ``` haskell
-type SubcommandConfig
-  =  "app" :-> ConfigP'
-  :+ "test" :-> TestConfigP
+type SubcommandConfig =
+  "app" :-> ConfigP'
+    :+ "test" :-> TestConfigP
 ```
 
 The `+` here stands for sum. The associated option type is:
 
 ``` haskell
 subcommandOpt :: SubcommandConfig Opt
-subcommandOpt
-  = configOpt4 :+ testConfigOpt :+ ANil
+subcommandOpt =
+  configOpt4 :+ testConfigOpt :+ ANil
 ```
 
 The `ANil` here marks the end of the association list (which is a heterogeneous
@@ -622,17 +621,19 @@
 getSubcommand = do
   result <- execCommandsDef subcommandOpt
   case result of
-    HereF (db :* service :* dir)
-      -> print $ runIdentity $
-           Config
-           <$> getNested db
-           <*> getNested service
-           <*> getSingle dir
-    ThereF (HereF (foo :* bar))
-      -> print $ runIdentity $
-           TestConfig
-           <$> getSingle foo
-           <*> getSingle bar
+    HereF (db :* service :* dir) ->
+      print $
+        runIdentity $
+          Config
+            <$> getNested db
+            <*> getNested service
+            <*> getSingle dir
+    ThereF (HereF (foo :* bar)) ->
+      print $
+        runIdentity $
+          TestConfig
+            <$> getSingle foo
+            <*> getSingle bar
 ```
 
 Or use `fromVariantF`, which is similar to the `either` function:
@@ -641,32 +642,35 @@
 getSubcommand' :: IO ()
 getSubcommand' = do
   result <- execCommandsDef subcommandOpt
-  fromVariantF result
-    (\(db :* service :* dir)
-       -> print $ runIdentity $
+  fromVariantF
+    result
+    ( \(db :* service :* dir) ->
+        print $
+          runIdentity $
             Config
-            <$> getNested db
-            <*> getNested service
-            <*> getSingle dir
+              <$> getNested db
+              <*> getNested service
+              <*> getSingle dir
     )
-    (\(foo :* bar)
-       -> print $ runIdentity $
+    ( \(foo :* bar) ->
+        print $
+          runIdentity $
             TestConfig
-            <$> getSingle foo
-            <*> getSingle bar
+              <$> getSingle foo
+              <*> getSingle bar
     )
 ```
 
 The type of `fromVariantF` can be thought of as being:
 
 ``` hs
-fromVariantF
-  :: VariantF '[a, b, c, ...] f
-  -> (a f -> r)
-  -> (b f -> r)
-  -> (c f -> r)
-  -> ...
-  -> r
+fromVariantF ::
+  VariantF '[a, b, c, ...] f ->
+  (a f -> r) ->
+  (b f -> r) ->
+  (c f -> r) ->
+  ... ->
+  r
 ```
 
 The signature will accept the appropriate number of functions depending on the
@@ -689,50 +693,52 @@
 First of all, let's use `FlatConfig` from the first example:
 
 ``` hs
-data FlatConfig
-  = FlatConfig
-      { _fcDbHost :: String
-      , _fcDbPort :: Int
-      , _fcDir    :: String
-      , _fcLog    :: Bool  -- whether to log or not
-      }
+data FlatConfig = FlatConfig
+  { _fcDbHost :: String,
+    _fcDbPort :: Int,
+    _fcDir :: String,
+    _fcLog :: Bool -- whether to log or not
+  }
   deriving (Show, Generic)
 
 dbHostOpt :: Opt String
-dbHostOpt
-  = option strParser
-      ( long "host"
-      . short 'h'
-      . metavar "DB_HOST"
-      . help "The database host"
-      )
+dbHostOpt =
+  option
+    strParser
+    ( long "host"
+        . short 'h'
+        . metavar "DB_HOST"
+        . help "The database host"
+    )
 
 dbPortOpt :: Opt Int
-dbPortOpt
-  = option readParser
-      ( long "port"
-      . help "The database port"
-      . envVar "DB_PORT"
-      . defaultVal 5432
-      )
+dbPortOpt =
+  option
+    readParser
+    ( long "port"
+        . help "The database port"
+        . envVar "DB_PORT"
+        . defaultVal 5432
+    )
 
 dirOpt :: Opt String
-dirOpt
-  = argument strParser
-      ( help "Some directory"
-      . defaultVal "/home/user/something"
-      )
+dirOpt =
+  argument
+    strParser
+    ( help "Some directory"
+        . defaultVal "/home/user/something"
+    )
 
 logOpt :: Opt Bool
-logOpt
-  = switch
-      ( long "log"
-      . help "Whether to log or not"
-      )
+logOpt =
+  switch
+    ( long "log"
+        . help "Whether to log or not"
+    )
 
 flatConfigOpt3 :: HKD FlatConfig Opt
-flatConfigOpt3
-  = build @FlatConfig dbHostOpt dbPortOpt dirOpt logOpt
+flatConfigOpt3 =
+  build @FlatConfig dbHostOpt dbPortOpt dirOpt logOpt
 ```
 
 To use the JSON source, a `FromJSON` instance is required. Thankfully that's
@@ -757,16 +763,17 @@
 
 ``` haskell
 sourceOpt :: (EnvSource :* JSONSource) Opt
-sourceOpt
-  = EnvSource :* JSONSource jsonOpt
+sourceOpt =
+  EnvSource :* JSONSource jsonOpt
   where
     jsonOpt :: Opt ConfigFile
-    jsonOpt
-      = option strParser
-          ( long "json"
-          . short 'j'
-          . help "JSON config filepath"
-          )
+    jsonOpt =
+      option
+        strParser
+        ( long "json"
+            . short 'j'
+            . help "JSON config filepath"
+        )
 ```
 
 Here, the type of the option for the JSON source is `ConfigFile`. This type is a
@@ -783,11 +790,12 @@
 
 ``` haskell
 jsonOpt :: Opt ConfigFile
-jsonOpt
-  = option strParser
-      ( long "json"
-      . defaultVal NoConfigFile
-      )
+jsonOpt =
+  option
+    strParser
+    ( long "json"
+        . defaultVal NoConfigFile
+    )
 ```
 
 Also, because `ConfigFile` has an `IsString` instance, there's no need to say
diff --git a/harg.cabal b/harg.cabal
--- a/harg.cabal
+++ b/harg.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               harg
-version:            0.4.2.1
+version:            0.5.0.0
 license:            BSD-3-Clause
 license-file:       LICENSE
 copyright:          Copyright (c) 2020 Alex Peitsinis
@@ -23,6 +23,13 @@
     type:     git
     location: https://github.com/alexpeits/harg
 
+flag builddocstest
+    description:
+        Build files in docs/ using markdown-unlit to test that examples are synced to the code
+        and working. This should only be enabled on CI.
+
+    default:     False
+
 library
     exposed-modules:
         Options.Harg
@@ -61,11 +68,11 @@
     build-depends:
         base >=4.7 && <5,
         aeson >=1.4.2 && <1.5,
-        barbies >=1.1.0 && <1.2,
+        barbies >=2.0.3 && <2.1,
         bytestring >=0.10.8 && <0.11,
         directory >=1.3.3 && <1.4,
-        higgledy >=0.3.0 && <0.4,
-        optparse-applicative >=0.14.3 && <0.15,
+        higgledy >=0.4.1 && <0.5,
+        optparse-applicative >=0.15.1 && <0.16,
         split >=0.2.3 && <0.3,
         text >=1.2.3 && <1.3,
         yaml >=0.11.0 && <0.12
@@ -84,11 +91,10 @@
         harg -any
 
 test-suite docs-test
-    type:               exitcode-stdio-1.0
-    main-is:            docs.lhs
-    build-tool-depends: markdown-unlit:markdown-unlit -any
-    hs-source-dirs:     docs
-    default-language:   Haskell2010
+    type:             exitcode-stdio-1.0
+    main-is:          docs.lhs
+    hs-source-dirs:   docs
+    default-language: Haskell2010
     ghc-options:
         -Wall -Wno-unticked-promoted-constructors -threaded -Wall
         -fno-warn-incomplete-patterns -fno-warn-missing-signatures
@@ -100,5 +106,11 @@
         aeson -any,
         barbies -any,
         higgledy -any,
+        markdown-unlit -any,
         optparse-applicative -any,
         harg -any
+
+    if flag(builddocstest)
+        buildable: True
+    else
+        buildable: False
diff --git a/src/Options/Harg.hs b/src/Options/Harg.hs
--- a/src/Options/Harg.hs
+++ b/src/Options/Harg.hs
@@ -81,7 +81,7 @@
     -- *** barbies
     B.FunctorB,
     B.TraversableB,
-    B.ProductB,
+    B.ApplicativeB,
     B.Rec (..),
 
     -- *** higgledy
@@ -93,7 +93,7 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import qualified Data.Generic.HKD as HKD
 import Options.Harg.Construct
 import Options.Harg.Het.HList
diff --git a/src/Options/Harg/Cmdline.hs b/src/Options/Harg/Cmdline.hs
--- a/src/Options/Harg/Cmdline.hs
+++ b/src/Options/Harg/Cmdline.hs
@@ -3,8 +3,8 @@
   )
 where
 
+import qualified Barbies as B
 import Control.Applicative ((<|>))
-import qualified Data.Barbie as B
 import Data.Functor.Compose (Compose (..))
 import Data.List (foldl')
 import Data.Maybe (fromMaybe)
@@ -19,7 +19,7 @@
   forall f a.
   ( Applicative f,
     B.TraversableB a,
-    B.ProductB a
+    B.ApplicativeB a
   ) =>
   -- | Source results
   [a (Compose Maybe f)] ->
diff --git a/src/Options/Harg/Config.hs b/src/Options/Harg/Config.hs
--- a/src/Options/Harg/Config.hs
+++ b/src/Options/Harg/Config.hs
@@ -4,7 +4,7 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import Data.Functor.Compose (Compose (..))
 import Data.Kind (Type)
 import qualified Options.Applicative as Optparse
@@ -20,7 +20,7 @@
   forall f c.
   ( Applicative f,
     B.TraversableB c,
-    B.ProductB c
+    B.ApplicativeB c
   ) =>
   HargCtx ->
   c (Compose Opt f) ->
diff --git a/src/Options/Harg/Construct.hs b/src/Options/Harg/Construct.hs
--- a/src/Options/Harg/Construct.hs
+++ b/src/Options/Harg/Construct.hs
@@ -23,6 +23,16 @@
     strParser,
     boolParser,
     manyParser,
+    HasLong,
+    HasShort,
+    HasHelp,
+    HasMetavar,
+    HasEnvVar,
+    HasDefaultVal,
+    HasDefaultStr,
+    HasRequired,
+    HasOptional,
+    IsOpt,
   )
 where
 
diff --git a/src/Options/Harg/Het/HList.hs b/src/Options/Harg/Het/HList.hs
--- a/src/Options/Harg/Het/HList.hs
+++ b/src/Options/Harg/Het/HList.hs
@@ -12,7 +12,7 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import Data.Kind (Type)
 import GHC.TypeLits (ErrorMessage (..), Symbol, TypeError)
 
diff --git a/src/Options/Harg/Het/Prod.hs b/src/Options/Harg/Het/Prod.hs
--- a/src/Options/Harg/Het/Prod.hs
+++ b/src/Options/Harg/Het/Prod.hs
@@ -12,9 +12,9 @@
   )
 where
 
+import qualified Barbies as B
 import Data.Aeson ((.!=), (.:?))
 import qualified Data.Aeson as JSON
-import qualified Data.Barbie as B
 import Data.Functor.Identity (Identity)
 import Data.Kind (Type)
 import Data.Proxy (Proxy (..))
@@ -40,7 +40,7 @@
   )
     (f :: Type -> Type)
   = a f :* b f
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 
 infixr 4 :*
 
@@ -69,17 +69,17 @@
 instance B.TraversableB a => B.TraversableB (Tagged t a) where
   btraverse nat (Tagged x) = Tagged <$> B.btraverse nat x
 
-instance B.ProductB a => B.ProductB (Tagged t a) where
+instance B.ApplicativeB a => B.ApplicativeB (Tagged t a) where
   bprod (Tagged l) (Tagged r) = Tagged (B.bprod l r)
-  buniq f = Tagged (B.buniq f)
+  bpure f = Tagged (B.bpure f)
 
 -- The following JSON instances need to work if and only if all elements in
 -- the product are `Tagged`, hence the weird pattern matches
 instance
   ( JSON.FromJSON (a Maybe),
     JSON.FromJSON (b' Maybe),
-    B.ProductB a,
-    B.ProductB b',
+    B.ApplicativeB a,
+    B.ApplicativeB b',
     KnownSymbol ta,
     b' ~ (Tagged tb b :* c)
   ) =>
@@ -89,14 +89,14 @@
     JSON.withObject ":*" $
       \o ->
         (:*)
-          <$> o .:? Tx.pack (symbolVal (Proxy :: Proxy ta)) .!= B.buniq Nothing
+          <$> o .:? Tx.pack (symbolVal (Proxy :: Proxy ta)) .!= B.bpure Nothing
           <*> JSON.parseJSON (JSON.Object o)
 
 instance
   ( JSON.FromJSON (a Maybe),
     JSON.FromJSON (b Maybe),
-    B.ProductB a,
-    B.ProductB b,
+    B.ApplicativeB a,
+    B.ApplicativeB b,
     KnownSymbol ta,
     KnownSymbol tb
   ) =>
@@ -106,5 +106,5 @@
     JSON.withObject ":*" $
       \o ->
         (:*)
-          <$> o .:? Tx.pack (symbolVal (Proxy :: Proxy ta)) .!= B.buniq Nothing
-          <*> o .:? Tx.pack (symbolVal (Proxy :: Proxy tb)) .!= B.buniq Nothing
+          <$> o .:? Tx.pack (symbolVal (Proxy :: Proxy ta)) .!= B.bpure Nothing
+          <*> o .:? Tx.pack (symbolVal (Proxy :: Proxy tb)) .!= B.bpure Nothing
diff --git a/src/Options/Harg/Het/Variant.hs b/src/Options/Harg/Het/Variant.hs
--- a/src/Options/Harg/Het/Variant.hs
+++ b/src/Options/Harg/Het/Variant.hs
@@ -16,7 +16,7 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import Data.Kind (Type)
 import Options.Harg.Het.Nat
 
diff --git a/src/Options/Harg/Nested.hs b/src/Options/Harg/Nested.hs
--- a/src/Options/Harg/Nested.hs
+++ b/src/Options/Harg/Nested.hs
@@ -15,8 +15,8 @@
   )
 where
 
+import qualified Barbies as B
 import qualified Data.Aeson as JSON
-import qualified Data.Barbie as B
 import Data.Coerce (Coercible, coerce)
 import Data.Functor.Identity (Identity (..))
 import qualified Data.Generic.HKD as HKD
@@ -100,7 +100,7 @@
 
 deriving newtype instance B.FunctorB (HKD.HKD b) => B.FunctorB (Nested b)
 
-deriving newtype instance B.ProductB (HKD.HKD b) => B.ProductB (Nested b)
+deriving newtype instance B.ApplicativeB (HKD.HKD b) => B.ApplicativeB (Nested b)
 
 instance (B.TraversableB (HKD.HKD b)) => B.TraversableB (Nested b) where
   btraverse nat (Nested hkd) = Nested <$> B.btraverse nat hkd
diff --git a/src/Options/Harg/Operations.hs b/src/Options/Harg/Operations.hs
--- a/src/Options/Harg/Operations.hs
+++ b/src/Options/Harg/Operations.hs
@@ -16,7 +16,7 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import Data.Functor.Identity (Identity (..))
 import qualified Options.Applicative as Optparse
 import Options.Harg.Cmdline (mkOptparseParser)
@@ -43,9 +43,9 @@
 execOptWithCtx ::
   forall c a.
   ( B.TraversableB a,
-    B.ProductB a,
+    B.ApplicativeB a,
     B.TraversableB c,
-    B.ProductB c,
+    B.ApplicativeB c,
     GetSource c Identity,
     RunSource (SourceVal c) a
   ) =>
@@ -81,9 +81,9 @@
 execOpt ::
   forall c a.
   ( B.TraversableB a,
-    B.ProductB a,
+    B.ApplicativeB a,
     B.TraversableB c,
-    B.ProductB c,
+    B.ApplicativeB c,
     GetSource c Identity,
     RunSource (SourceVal c) a
   ) =>
@@ -101,7 +101,7 @@
 execOptWithCtxDef ::
   forall a.
   ( B.TraversableB a,
-    B.ProductB a
+    B.ApplicativeB a
   ) =>
   -- | Context containing the environment and the cmdline args
   HargCtx ->
@@ -115,7 +115,7 @@
 execOptDef ::
   forall a.
   ( B.TraversableB a,
-    B.ProductB a
+    B.ApplicativeB a
   ) =>
   -- | Target configuration options
   a Opt ->
@@ -129,7 +129,7 @@
   forall c ts xs.
   ( B.TraversableB (VariantF xs),
     B.TraversableB c,
-    B.ProductB c,
+    B.ApplicativeB c,
     Subcommands ts xs,
     GetSource c Identity,
     All (RunSource (SourceVal (c :* HiddenSources))) xs,
@@ -173,7 +173,7 @@
   forall c ts xs.
   ( B.TraversableB (VariantF xs),
     B.TraversableB c,
-    B.ProductB c,
+    B.ApplicativeB c,
     Subcommands ts xs,
     GetSource c Identity,
     All (RunSource (SourceVal (c :* HiddenSources))) xs,
diff --git a/src/Options/Harg/Single.hs b/src/Options/Harg/Single.hs
--- a/src/Options/Harg/Single.hs
+++ b/src/Options/Harg/Single.hs
@@ -11,8 +11,8 @@
   )
 where
 
+import qualified Barbies as B
 import qualified Data.Aeson as JSON
-import qualified Data.Barbie as B
 import Data.Functor.Identity (Identity (..))
 import qualified Data.Functor.Product as P
 import Data.Kind (Type)
@@ -57,6 +57,6 @@
 instance B.TraversableB (Single a) where
   btraverse nat (Single p) = Single <$> nat p
 
-instance B.ProductB (Single a) where
+instance B.ApplicativeB (Single a) where
   bprod (Single l) (Single r) = Single (P.Pair l r)
-  buniq = Single
+  bpure = Single
diff --git a/src/Options/Harg/Sources.hs b/src/Options/Harg/Sources.hs
--- a/src/Options/Harg/Sources.hs
+++ b/src/Options/Harg/Sources.hs
@@ -7,7 +7,7 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import Data.Foldable (foldr')
 import Data.Functor.Compose (Compose (..))
 import Options.Harg.Sources.DefaultStr (DefaultStrSource (..))
diff --git a/src/Options/Harg/Sources/DefaultStr.hs b/src/Options/Harg/Sources/DefaultStr.hs
--- a/src/Options/Harg/Sources/DefaultStr.hs
+++ b/src/Options/Harg/Sources/DefaultStr.hs
@@ -7,7 +7,7 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import Data.Functor.Compose (Compose (..))
 import Data.Kind (Type)
 import GHC.Generics (Generic)
@@ -17,7 +17,7 @@
 -- | Source that enables a parser to read options from defaults that are provided
 -- as strings (unparsed).
 data DefaultStrSource (f :: Type -> Type) = DefaultStrSource
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 
 -- | Value of 'DefaultStrSource' is a dummy value, as the default string option can
 -- be found inside the 'Opt' ('_optDefaultStr').
diff --git a/src/Options/Harg/Sources/Env.hs b/src/Options/Harg/Sources/Env.hs
--- a/src/Options/Harg/Sources/Env.hs
+++ b/src/Options/Harg/Sources/Env.hs
@@ -8,7 +8,7 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import Data.Functor.Compose (Compose (..))
 import Data.Kind (Type)
 import Data.List (find)
@@ -18,7 +18,7 @@
 
 -- | Source that enables a parser to read options from environment variables.
 data EnvSource (f :: Type -> Type) = EnvSource
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 
 -- | Value of 'EnvSource', which is an association list between environment
 -- variable names and values (strings).
diff --git a/src/Options/Harg/Sources/JSON.hs b/src/Options/Harg/Sources/JSON.hs
--- a/src/Options/Harg/Sources/JSON.hs
+++ b/src/Options/Harg/Sources/JSON.hs
@@ -8,8 +8,8 @@
   )
 where
 
+import qualified Barbies as B
 import qualified Data.Aeson as JSON
-import qualified Data.Barbie as B
 import qualified Data.ByteString.Lazy as LBS
 import Data.Functor.Compose (Compose (..))
 import Data.Functor.Identity (Identity (..))
@@ -20,7 +20,7 @@
 
 -- | Source that enables a parser to read options from a JSON file.
 newtype JSONSource f = JSONSource (f ConfigFile)
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 
 -- | The result of reading a JSON file. @JSONSourceNotRequired@ is used when
 -- the user has specified @defaultVal NoConfigFile@. It holds the contents of
diff --git a/src/Options/Harg/Sources/NoSource.hs b/src/Options/Harg/Sources/NoSource.hs
--- a/src/Options/Harg/Sources/NoSource.hs
+++ b/src/Options/Harg/Sources/NoSource.hs
@@ -8,14 +8,14 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import Data.Kind (Type)
 import GHC.Generics (Generic)
 import Options.Harg.Sources.Types
 
 -- | Throwaway type whose 'GetSource' instance returns no value.
 data NoSource (f :: Type -> Type) = NoSource
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 
 instance GetSource NoSource f where
   type SourceVal NoSource = ()
diff --git a/src/Options/Harg/Sources/YAML.hs b/src/Options/Harg/Sources/YAML.hs
--- a/src/Options/Harg/Sources/YAML.hs
+++ b/src/Options/Harg/Sources/YAML.hs
@@ -8,8 +8,8 @@
   )
 where
 
+import qualified Barbies as B
 import Control.Exception (displayException)
-import qualified Data.Barbie as B
 import qualified Data.ByteString as BS
 import Data.Functor.Compose (Compose (..))
 import Data.Functor.Identity (Identity (..))
@@ -21,7 +21,7 @@
 
 -- | Source that enables a parser to read options from a YAML file.
 newtype YAMLSource f = YAMLSource (f ConfigFile)
-  deriving (Generic, B.FunctorB, B.TraversableB, B.ProductB)
+  deriving (Generic, B.FunctorB, B.TraversableB, B.ApplicativeB)
 
 -- | The result of reading a YAML file. @YAMLSourceNotRequired@ is used when
 -- the user has specified @defaultVal NoConfigFile@. It holds the contents of
diff --git a/src/Options/Harg/Subcommands.hs b/src/Options/Harg/Subcommands.hs
--- a/src/Options/Harg/Subcommands.hs
+++ b/src/Options/Harg/Subcommands.hs
@@ -6,7 +6,7 @@
   )
 where
 
-import qualified Data.Barbie as B
+import qualified Barbies as B
 import Data.Functor.Compose (Compose (..))
 import Data.Kind (Type)
 import Data.Proxy (Proxy (..))
@@ -95,7 +95,7 @@
     -- get the correct injection into the variant by position
     InjectPosF n x (as ++ (x ': xs)),
     B.TraversableB x,
-    B.ProductB x,
+    B.ApplicativeB x,
     KnownSymbol t,
     -- prove that xs ++ (y : ys) ~ (xs ++ [y]) ++ ys
     Proof as x xs
diff --git a/src/Options/Harg/Util.hs b/src/Options/Harg/Util.hs
--- a/src/Options/Harg/Util.hs
+++ b/src/Options/Harg/Util.hs
@@ -9,8 +9,8 @@
   )
 where
 
+import qualified Barbies as B
 import qualified Control.Exception as Exc
-import qualified Data.Barbie as B
 import qualified Data.ByteString as BS
 import qualified Data.ByteString.Lazy.Char8 as LBS
 import Data.Functor.Compose (Compose (..))
