diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,4 @@
+## 0.1.0 (2024-04-10)
+Initial release.
+
+  * generic type-level `foldMap`
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2024 Ben Orchard (@raehik) <thefirstmuffinman@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+# generic-type-functions
+Type-level functions (type families) on the generic type representation that
+approximate familiar term-level functions.
+
+The type families take defunctionalization symbols that use phadej's
+[defun](https://hackage.haskell.org/package/defun-core) library.
+
+Too abstract to be of much use, but here it is all the same.
+
+## License
+Provided under the MIT license. See `LICENSE` for license text.
diff --git a/generic-type-functions.cabal b/generic-type-functions.cabal
new file mode 100644
--- /dev/null
+++ b/generic-type-functions.cabal
@@ -0,0 +1,50 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.35.2.
+--
+-- see: https://github.com/sol/hpack
+
+name:           generic-type-functions
+version:        0.1.0
+synopsis:       Familiar functions lifted to type-level functions on generic types
+description:    Please see README.md.
+category:       Generics, Types, Data
+homepage:       https://github.com/raehik/generic-type-functions#readme
+bug-reports:    https://github.com/raehik/generic-type-functions/issues
+author:         Ben Orchard
+maintainer:     Ben Orchard <thefirstmuffinman@gmail.com>
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    CHANGELOG.md
+
+source-repository head
+  type: git
+  location: https://github.com/raehik/generic-type-functions
+
+library
+  exposed-modules:
+      Generic.Type.Example
+      Generic.Type.Function.FoldMap
+  other-modules:
+      Paths_generic_type_functions
+  hs-source-dirs:
+      src
+  default-extensions:
+      LambdaCase
+      NoStarIsType
+      DerivingVia
+      DeriveAnyClass
+      GADTs
+      RoleAnnotations
+      DefaultSignatures
+      TypeFamilies
+      DataKinds
+      MagicHash
+  ghc-options: -Wall
+  build-depends:
+      base >=4.14 && <5
+    , defun-core ==0.1.*
+  default-language: GHC2021
diff --git a/src/Generic/Type/Example.hs b/src/Generic/Type/Example.hs
new file mode 100644
--- /dev/null
+++ b/src/Generic/Type/Example.hs
@@ -0,0 +1,24 @@
+-- {-# LANGUAGE UndecidableInstances #-}
+
+module Generic.Type.Example where
+
+import DeFun.Core ( type (~>), type App )
+import GHC.Generics ( Generic )
+import GHC.TypeNats ( type (+), type Natural )
+
+type FieldCountSym :: a ~> Natural
+data FieldCountSym a
+type instance App FieldCountSym a = 1
+
+type PlusSym :: Natural ~> Natural ~> Natural
+data PlusSym f
+type instance App PlusSym f = PlusSym1 f
+
+type PlusSym1 :: Natural -> Natural ~> Natural
+data PlusSym1 l r
+type instance App (PlusSym1 l) r = l + r
+
+data X3Fields = X3Fields { x3Fields1 :: (), x3Fields2 :: (), x3Fields3 :: () }
+    deriving stock Generic
+
+-- > k! GTFoldMapC PlusSym 5 FieldCountSym (Rep X3Fields) = 3
diff --git a/src/Generic/Type/Function/FoldMap.hs b/src/Generic/Type/Function/FoldMap.hs
new file mode 100644
--- /dev/null
+++ b/src/Generic/Type/Function/FoldMap.hs
@@ -0,0 +1,24 @@
+{-# LANGUAGE UndecidableInstances #-}
+
+module Generic.Type.Function.FoldMap where
+
+import DeFun.Core ( type (~>), type (@@) )
+import Data.Kind ( type Type )
+import GHC.Generics
+
+-- | 'foldMap' on generic type representations (field product level).
+--
+-- Will work for single-constructor types as well thanks to meta unwrapping.
+type GTFoldMapC
+    :: (m ~> m ~> m) -- | type-level 'mappend' defun symbol
+    -> m             -- | type-level 'mempty'
+    -> (Type ~> m)   -- | base case defun symbol
+    -> (k -> Type)   -- | generic representation (field product level)
+    -> m
+type family GTFoldMapC tmappend tmempty f gf where
+    GTFoldMapC tmappend tmempty f U1          = tmempty
+    GTFoldMapC tmappend tmempty f (K1 i c)    = f @@ c
+    GTFoldMapC tmappend tmempty f (l :*: r)   = tmappend
+        @@ GTFoldMapC tmappend tmempty f l
+        @@ GTFoldMapC tmappend tmempty f r
+    GTFoldMapC tmappend tmempty f (M1 _ _ gf) = GTFoldMapC tmappend tmempty f gf
