diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Revision history for constable
+
+## 0.1.0.0 -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2022, Aaron Allen
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Aaron Allen nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/constable.cabal b/constable.cabal
new file mode 100644
--- /dev/null
+++ b/constable.cabal
@@ -0,0 +1,41 @@
+cabal-version:      3.0
+name:               constable
+version:            0.1.0.0
+synopsis: A safe interface for Const summarization
+description: A safe interface for using the @Const@ functor to do summarization. See the @Constable@ module for details.
+license:            BSD-3-Clause
+license-file:       LICENSE
+author:             Aaron Allen
+maintainer:         aaronallen8455@gmail.com
+bug-reports:        https://github.com/aaronallen8455/constable/issues
+-- copyright:
+category:           Development
+build-type:         Simple
+extra-doc-files:    CHANGELOG.md
+-- extra-source-files:
+
+common warnings
+    ghc-options: -Wall
+                 -Wno-unticked-promoted-constructors
+
+library
+    import:           warnings
+    exposed-modules:  Constable
+    -- other-modules:
+    -- other-extensions:
+    build-depends:    base <= 5
+    hs-source-dirs:   src
+    default-language: Haskell2010
+
+test-suite constable-test
+    import:           warnings
+    default-language: Haskell2010
+    -- other-modules:
+    -- other-extensions:
+    type:             exitcode-stdio-1.0
+    hs-source-dirs:   test
+    main-is:          Main.hs
+    build-depends:
+        base,
+        constable,
+        doctest
diff --git a/src/Constable.hs b/src/Constable.hs
new file mode 100644
--- /dev/null
+++ b/src/Constable.hs
@@ -0,0 +1,118 @@
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeFamilies #-}
+{-| This module provides an interface for the 'Const.Const' functor which facilitates
+   using it safely for summarization via the applicative instance @Monoid m => Applicative (Const m)@.
+
+   As an example, say we have a record of numbers and a function that sums up
+   the fields of that record. We want to leverage the type system to ensure
+   that if the record changes (field are added or removed), then the summing
+   function will not compile until it is updated to match.
+
+   As a first attempt, we might write something like this:
+
+   @
+   import Data.Functor.Const
+   import Data.Monoid
+
+   data Parts = MkParts
+     { part1 :: Int
+     , part2 :: Int
+     , part3 :: Int
+     }
+
+   sumParts :: Parts -> Int
+   sumParts parts = getSum . getConst '$'
+     MkParts
+       '<$>' Const (Sum $ part1 parts)
+       '<*>' Const (Sum $ part2 parts)
+       '<*>' Const (Sum $ part3 parts)
+   @
+
+   At first glance it looks like this accomplishes our goal, but there is a
+   serious bug. If we remove a field from the record then @sumParts@ will
+   indeed fail to compile, but if we add a field then it will compile without
+   issue! This is because we didn't explicitly provide a type to the @Const@
+   expression being constructed and so the compiler infers it to be a function
+   type rather than the fully applied type that we expect. This means we must
+   always remember to add explicit type signatures or type applications
+   anywhere we use this pattern.
+
+   If we instead use the 'getConstSafe' version of 'Const.getConst' exported by this
+   module then we don't need to worry about this issue because the compiler
+   will complain if the inferred type of a @Const@ is for a function type.
+
+   If you use HLint, you can go one step further and ban the use of the
+   "unsafe" 'Const.getConst' in your codebase by way of an HLint rule:
+
+   @
+   - functions:
+     - {name: getConst, within: []}
+   @
+-}
+module Constable
+  ( -- * API
+    getConstSafe
+  , mkConst
+  , mkConstF
+  , Const.Const(Constable.Const)
+  -- * Internal
+  , FullyAppliedConst
+  ) where
+
+import           Data.Coerce (coerce)
+import qualified Data.Functor.Const as Const
+import           Data.Kind (Type, Constraint)
+import           GHC.TypeLits (TypeError, ErrorMessage(..))
+
+-- | A constraint enforcing that 'getConstSafe' is only used with non-partially
+-- applied constructors.
+type family FullyAppliedConst (a :: Type) :: Constraint where
+  FullyAppliedConst (a -> b) =
+    TypeError (Text "Const used with partially applied constructor: '"
+          :<>: ShowType (a -> b)
+          :<>: Text "'")
+  FullyAppliedConst a = ()
+
+-- | Unwraps 'Const.Const'. Throws a type error if that 'Const.Const' has a
+-- function type for its second argument.
+getConstSafe :: FullyAppliedConst b => Const.Const a b -> a
+getConstSafe = coerce
+
+-- | Smart constructor for 'Const.Const' that enforces that the value it contains is
+-- built from a value of the result type. This provides an extra measure of type safety.
+--
+-- @
+-- data Summable = MkSummable
+--   { s1 :: Int
+--   , s2 :: Double
+--   , s3 :: Integer
+--   } deriving (Show)
+--
+-- test :: Summable
+-- test = Summable
+--   { s1 = 1
+--   , s2 = 2
+--   , s3 = 3
+--   }
+--
+-- 'getConstSafe' '$' MkSummable
+--   '<$>' mkConst (s1 test) (Sum . fromIntegral)
+--   '<*>' mkConst (s2 test) Sum
+--   '<*>' mkConst (s3 test) (Sum . fromIntegral)
+-- @
+mkConst :: a -> (a -> m) -> Const.Const m a
+mkConst a toM = coerce (toM a)
+
+-- | Smart constructor for 'Const.Const' like 'mkConst' but where the argument is the
+-- result type applied to some type constructor @f@.
+mkConstF :: f a -> (f a -> m) -> Const.Const m a
+mkConstF fa toM = coerce (toM fa)
+
+-- | A pattern synonym for 'Const.Const' that upholds the fully applied
+-- constructor invariant for its second type argument.
+pattern Const :: FullyAppliedConst b => a -> Const.Const a b
+pattern Const a = Const.Const a
+{-# COMPLETE Const #-}
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,4 @@
+import           Test.DocTest
+
+main :: IO ()
+main = doctest [ "-isrc" , "test/Test.hs" ]
