diff --git a/Changelog.md b/Changelog.md
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,15 @@
 # NEXT
 
+# 0.4.4
+
+* Add `Alpha` and `Subst` instances for `NonEmpty`.  Thanks Brent Yorgey (byorgey)
+* Add GHC 9.8 to CI matrix
+* Bump `base` >= 4.9
+* Remove `tested-with: 7.x` in `unbound-generics.cabal`. We removed CI testing with GHC 7.x last year.
+* Move GSubst from `Unbound.Generics.LocallyNameless.Subst` into a separate `Internal` module that is exported. Now users can write their own generic traversals.
+  Thanks Bohdan Liesnikov (liesnikov)
+* Welcome Austin Erlandson (erlandsona) as a maintainer
+
 # 0.4.3
 
 * Add an `instantiate` function that substitutes a list of terms for a collection of bound variables in a toplevel `Bind p t` term.
diff --git a/src/Unbound/Generics/LocallyNameless/Alpha.hs b/src/Unbound/Generics/LocallyNameless/Alpha.hs
--- a/src/Unbound/Generics/LocallyNameless/Alpha.hs
+++ b/src/Unbound/Generics/LocallyNameless/Alpha.hs
@@ -60,6 +60,7 @@
 import Data.Functor.Contravariant (Contravariant(..))
 import Data.Foldable (Foldable(..))
 import Data.List (intersect)
+import Data.List.NonEmpty (NonEmpty)
 import Data.Monoid (Monoid(..), All(..))
 import Data.Ratio (Ratio)
 import Data.Semigroup as Sem
@@ -687,6 +688,7 @@
 
 instance Alpha a => Alpha (Maybe a)
 instance Alpha a => Alpha [a]
+instance Alpha a => Alpha (NonEmpty a)
 instance Alpha ()
 instance (Alpha a,Alpha b) => Alpha (Either a b)
 instance (Alpha a,Alpha b) => Alpha (a,b)
diff --git a/src/Unbound/Generics/LocallyNameless/Internal/GSubst.hs b/src/Unbound/Generics/LocallyNameless/Internal/GSubst.hs
new file mode 100644
--- /dev/null
+++ b/src/Unbound/Generics/LocallyNameless/Internal/GSubst.hs
@@ -0,0 +1,60 @@
+-- |
+-- Module     : Unbound.Generics.LocallyNameless.Subst
+-- Copyright  : (c) 2014, Aleksey Kliger
+-- License    : BSD3 (See LICENSE)
+-- Maintainer : Aleksey Kliger
+-- Stability  : experimental
+--
+-- A typeclass for generic structural substitution.
+
+{-# LANGUAGE
+               FlexibleInstances
+             , MultiParamTypeClasses
+             , TypeOperators
+ #-}
+
+module Unbound.Generics.LocallyNameless.Internal.GSubst (
+  GSubst(..)
+  ) where
+
+import GHC.Generics
+
+import Unbound.Generics.LocallyNameless.Name
+import Unbound.Generics.LocallyNameless.Alpha
+
+---- generic structural substitution.
+
+class GSubst b f where
+  gsubst :: Name b -> b -> f c -> f c
+  gsubsts :: [(Name b, b)] -> f c -> f c
+  gsubstBvs :: AlphaCtx -> [b] -> f c -> f c
+
+instance GSubst b f => GSubst b (M1 i c f) where
+  gsubst nm val = M1 . gsubst nm val . unM1
+  gsubsts ss = M1 . gsubsts ss . unM1
+  gsubstBvs c b = M1 . gsubstBvs c b . unM1
+
+instance GSubst b U1 where
+  gsubst _nm _val _ = U1
+  gsubsts _ss _ = U1
+  gsubstBvs _c _b _ = U1
+
+instance GSubst b V1 where
+  gsubst _nm _val = id
+  gsubsts _ss = id
+  gsubstBvs _c _b = id
+
+instance (GSubst b f, GSubst b g) => GSubst b (f :*: g) where
+  gsubst nm val (f :*: g) = gsubst nm val f :*: gsubst nm val g
+  gsubsts ss (f :*: g) = gsubsts ss f :*: gsubsts ss g
+  gsubstBvs c b (f :*: g) = gsubstBvs c b f :*: gsubstBvs c b g
+
+instance (GSubst b f, GSubst b g) => GSubst b (f :+: g) where
+  gsubst nm val (L1 f) = L1 $ gsubst nm val f
+  gsubst nm val (R1 g) = R1 $ gsubst nm val g
+
+  gsubsts ss (L1 f) = L1 $ gsubsts ss f
+  gsubsts ss (R1 g) = R1 $ gsubsts ss g
+
+  gsubstBvs c b (L1 f) = L1 $ gsubstBvs c b f
+  gsubstBvs c b (R1 g) = R1 $ gsubstBvs c b g
diff --git a/src/Unbound/Generics/LocallyNameless/Subst.hs b/src/Unbound/Generics/LocallyNameless/Subst.hs
--- a/src/Unbound/Generics/LocallyNameless/Subst.hs
+++ b/src/Unbound/Generics/LocallyNameless/Subst.hs
@@ -53,6 +53,7 @@
 import GHC.Generics
 
 import Data.List (find)
+import Data.List.NonEmpty (NonEmpty)
 
 import Unbound.Generics.LocallyNameless.Name
 import Unbound.Generics.LocallyNameless.Alpha
@@ -62,13 +63,14 @@
 import Unbound.Generics.LocallyNameless.Bind
 import Unbound.Generics.LocallyNameless.Rebind
 import Unbound.Generics.LocallyNameless.Rec
+import Unbound.Generics.LocallyNameless.Internal.GSubst
 
 -- | See 'isVar'
 data SubstName a b where
   SubstName :: (a ~ b) => Name a -> SubstName a b
 
--- | See 'isCoerceVar'  
-data SubstCoerce a b where  
+-- | See 'isCoerceVar'
+data SubstCoerce a b where
   SubstCoerce :: Name b -> (b -> Maybe a) -> SubstCoerce a b
 
 -- | Immediately substitute for the bound variables of a pattern
@@ -91,7 +93,7 @@
   isvar :: a -> Maybe (SubstName a b)
   isvar _ = Nothing
 
-  -- | This is an alternative version to 'isvar', useable in the case 
+  -- | This is an alternative version to 'isvar', useable in the case
   --   that the substituted argument doesn't have *exactly* the same type
   --   as the term it should be substituted into.
   --   The default implementation always returns 'Nothing'.
@@ -117,7 +119,7 @@
     | all (isFreeName . fst) ss =
       case (isvar x :: Maybe (SubstName a b)) of
         Just (SubstName m) | Just (_, u) <- find ((==m) . fst) ss -> u
-        _ -> case isCoerceVar x :: Maybe (SubstCoerce a b) of 
+        _ -> case isCoerceVar x :: Maybe (SubstCoerce a b) of
             Just (SubstCoerce m f) | Just (_, u) <- find ((==m) . fst) ss -> maybe x id (f u)
             _ -> to $ gsubsts ss (from x)
     | otherwise =
@@ -134,48 +136,11 @@
         Just (SubstName (Bn j k)) | ctxLevel ctx == j, fromInteger k < length bs -> bs !! fromInteger k
         _ -> to $ gsubstBvs ctx bs (from x)
 
----- generic structural substitution.
-
-class GSubst b f where
-  gsubst :: Name b -> b -> f c -> f c
-  gsubsts :: [(Name b, b)] -> f c -> f c
-  gsubstBvs :: AlphaCtx -> [b] -> f c -> f c
-
 instance Subst b c => GSubst b (K1 i c) where
   gsubst nm val = K1 . subst nm val . unK1
   gsubsts ss = K1 . substs ss . unK1
   gsubstBvs ctx b = K1 . substBvs ctx b . unK1
 
-instance GSubst b f => GSubst b (M1 i c f) where
-  gsubst nm val = M1 . gsubst nm val . unM1
-  gsubsts ss = M1 . gsubsts ss . unM1
-  gsubstBvs c b = M1 . gsubstBvs c b . unM1
-
-instance GSubst b U1 where
-  gsubst _nm _val _ = U1
-  gsubsts _ss _ = U1
-  gsubstBvs _c _b _ = U1
-
-instance GSubst b V1 where
-  gsubst _nm _val = id
-  gsubsts _ss = id
-  gsubstBvs _c _b = id
-
-instance (GSubst b f, GSubst b g) => GSubst b (f :*: g) where
-  gsubst nm val (f :*: g) = gsubst nm val f :*: gsubst nm val g
-  gsubsts ss (f :*: g) = gsubsts ss f :*: gsubsts ss g
-  gsubstBvs c b (f :*: g) = gsubstBvs c b f :*: gsubstBvs c b g
-
-instance (GSubst b f, GSubst b g) => GSubst b (f :+: g) where
-  gsubst nm val (L1 f) = L1 $ gsubst nm val f
-  gsubst nm val (R1 g) = R1 $ gsubst nm val g
-
-  gsubsts ss (L1 f) = L1 $ gsubsts ss f
-  gsubsts ss (R1 g) = R1 $ gsubsts ss g
-
-  gsubstBvs c b (L1 f) = L1 $ gsubstBvs c b f
-  gsubstBvs c b (R1 g) = R1 $ gsubstBvs c b g
-
 -- these have a Generic instance, but
 -- it's self-refential (ie: Rep Int = D1 (C1 (S1 (Rec0 Int))))
 -- so our structural GSubst instances get stuck in an infinite loop.
@@ -186,7 +151,7 @@
 instance Subst b Float where subst _ _ = id ; substs _ = id ; substBvs _ _ = id
 instance Subst b Double where subst _ _ = id ; substs _ = id ; substBvs _ _ = id
 
--- huh, apparently there's no instance Generic Integer. 
+-- huh, apparently there's no instance Generic Integer.
 instance Subst b Integer where subst _ _ = id ; substs _ = id ; substBvs _ _ = id
 
 instance (Subst c a, Subst c b) => Subst c (a,b)
@@ -195,6 +160,7 @@
 instance (Subst c a, Subst c b, Subst c d, Subst c e, Subst c f) =>
    Subst c (a,b,d,e,f)
 instance (Subst c a) => Subst c [a]
+instance (Subst c a) => Subst c (NonEmpty a)
 instance (Subst c a) => Subst c (Maybe a)
 instance (Subst c a, Subst c b) => Subst c (Either a b)
 
diff --git a/unbound-generics.cabal b/unbound-generics.cabal
--- a/unbound-generics.cabal
+++ b/unbound-generics.cabal
@@ -1,6 +1,6 @@
 cabal-version:       >=1.10
 name:                unbound-generics
-version:             0.4.3
+version:             0.4.4
 synopsis:            Support for programming with names and binders using GHC Generics
 description:         Specify the binding structure of your data type with an
                      expressive set of type combinators, and unbound-generics
@@ -18,7 +18,7 @@
 bug-reports:         http://github.com/lambdageek/unbound-generics/issues
 license:             BSD3
 license-file:        LICENSE
-author:              Aleksey Kliger
+author:              Aleksey Kliger, Austin Erlandson
 maintainer:          aleksey@lambdageek.org
 copyright:           (c) 2014-2022, Aleksey Kliger
 category:            Language
@@ -28,7 +28,7 @@
                      README.md,
                      Changelog.md
 
-tested-with: GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7, GHC == 9.0.2, GHC == 9.2.*, GHC == 9.4.*
+tested-with: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7, GHC == 9.0.2, GHC == 9.2.*, GHC == 9.4.*, GHC == 9.8.*
 
 library
   exposed-modules:     Unbound.Generics.LocallyNameless
@@ -44,6 +44,7 @@
                        Unbound.Generics.LocallyNameless.Operations
                        Unbound.Generics.LocallyNameless.Unsafe
                        Unbound.Generics.LocallyNameless.Internal.Fold
+                       Unbound.Generics.LocallyNameless.Internal.GSubst
                        Unbound.Generics.LocallyNameless.Internal.Iso
                        Unbound.Generics.LocallyNameless.Internal.Lens
                        Unbound.Generics.LocallyNameless.Rec
@@ -52,16 +53,16 @@
                        Unbound.Generics.LocallyNameless.Subst
   -- other-modules:
   -- other-extensions:
-  build-depends:       base >=4.6 && <5,
+  build-depends:       base >=4.9 && <5,
                        template-haskell >= 2.8.0.0,
                        deepseq >= 1.3.0.0,
                        mtl >= 2.1,
                        transformers >= 0.3 && < 0.7,
                        transformers-compat >= 0.3,
-                       containers >= 0.5 && < 0.7,
+                       containers >= 0.5 && < 0.8,
                        contravariant >= 0.5,
                        profunctors >= 4.0,
-                       ansi-wl-pprint >= 0.6.7.2 && < 0.7,
+                       ansi-wl-pprint >= 0.6.7.2 && < 1.1,
                        exceptions >= 0.8 && < 0.11
   hs-source-dirs:      src
   default-language:    Haskell2010
