diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,13 @@
+# Changelog for typed-digits
+
+Notable changes to this project will be documented in this file.
+
+## Unreleased changes
+
+None.
+
+## 0.1.0.0 - 2019-12-12
+
+Alpha release.
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright 2019 Arran D. Stewart
+
+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,31 @@
+[![Build Status](https://travis-ci.org/arranstewart/hs-typed-digits.svg?branch=master)](https://travis-ci.org/arranstewart/hs-typed-digits)
+[![Hackage](https://img.shields.io/hackage/v/typed-digits.svg)](https://hackage.haskell.org/package/typed-digits)
+
+# typed-digits
+
+Provides a Digit type, with the base of the digit available
+as a type-level Nat. Thus, it can be guaranteed at compile-time
+that digits of different bases can't be added together.
+
+## Usage example
+
+For more convenient provision of type-level parameters,
+it's recommended to use the `DataKinds` and `TypeApplications` extensions.
+Then, you can give type-level parameters using `@`, as seen below, instead of
+giving the full type.
+
+```haskell
+>>> :set -XDataKinds -XTypeApplications
+>>> import Data.TypedDigits
+>>> let d = digit @9 3
+>>> d
+Just 3 (base 9)
+```
+
+## Source tree contents 
+
+-   `src`: Library source files
+-   `test`: Unit tests
+-   `doctest`: Documentation tests using [`doctest`](https://github.com/sol/doctest)
+
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/doctest/Main.hs b/doctest/Main.hs
new file mode 100644
--- /dev/null
+++ b/doctest/Main.hs
@@ -0,0 +1,19 @@
+{-# LANGUAGE CPP #-}
+
+import Test.DocTest
+import System.FilePath.Glob
+
+-- doctest >= 0.15.0 adds useful "--verbose" flag
+#if MIN_VERSION_doctest(0,15,0)
+hasVerbose = True
+#else
+hasVerbose = False
+#endif
+
+main = do
+  srcFiles <- globDir1 (compile "**/*.hs") "src"
+  let doctestOpts = if hasVerbose
+                    then ["-isrc", "--verbose"]
+                    else ["-isrc"]
+  doctest $ doctestOpts ++ srcFiles
+
diff --git a/src/Data/TypedDigits.hs b/src/Data/TypedDigits.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/TypedDigits.hs
@@ -0,0 +1,30 @@
+{-|
+
+Module      : Data.TypedDigits
+Description : Digits, indexed by their base at the type level
+Portability : portable
+
+= Description
+
+Digits, indexed by their base at the type level.
+
+-}
+
+module Data.TypedDigits (
+    Digit
+  -- * Constructing 'Digits'
+  , digit
+  , digit'
+  -- * Querying 'Digits'
+  , getVal  
+  , getBase
+  , getBaseT
+  -- * Arithmetic operations on 'Digits'
+  , (<+>)
+  , (<->)
+  , KnownNat
+  )
+  where
+
+import Data.TypedDigits.Internal
+
diff --git a/src/Data/TypedDigits/Internal.hs b/src/Data/TypedDigits/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/TypedDigits/Internal.hs
@@ -0,0 +1,121 @@
+
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+
+{-|
+
+Module      : Data.TypedDigits.Internal
+Description : Data.TypedDigits internals
+Portability : portable
+
+This module is considered internal, and may change
+without warning.
+The Package Versioning Policy does not apply to it.
+
+= Description
+
+Digits, indexed by their base at the type level.
+
+-}
+
+module Data.TypedDigits.Internal (
+    module Data.TypedDigits.Internal
+  , KnownNat 
+  )
+  where
+
+import Data.Maybe
+import Data.Proxy
+import Data.Singletons.TypeLits (Nat, Sing(..), KnownNat )
+import Data.Singletons          (singByProxy, SingI(..), fromSing )
+
+-- | digits, indexed by their base at the type level
+newtype Digit (base :: Nat) = Digit { getVal :: Int }
+
+-- | @getBaseT p@: if @p@ is of some type @a base@,
+-- then reflect the base into a value.
+--
+-- Useful for getting the base, just given a 'Proxy'; e.g.:
+--
+-- >>> :set -XDataKinds
+-- >>> :set -XTypeApplications
+-- >>> let p = Proxy :: Proxy 3
+-- >>> getBaseT p
+-- 3
+getBaseT :: forall a base . (KnownNat base) => a base -> Int
+getBaseT _ = fromIntegral $ fromSing s
+  where
+      s :: Sing base
+      s = singByProxy (Proxy :: Proxy base)
+
+
+-- | @digit x@: construct a digit. 0 <= @x@ < base must hold
+-- true.
+--
+-- Nicer if TypeApplications is enabled, then you can say:
+--
+-- >>> :set -XDataKinds
+-- >>> :set -XTypeApplications
+-- >>> digit @9 8
+-- Just 8 (base 9)
+digit :: forall base . (KnownNat base) => Int -> Maybe (Digit base)
+digit x = 
+    if x >= 0 && x < fromIntegral (getBaseT (Proxy :: Proxy base))
+    then Just $ Digit x
+    else Nothing
+
+-- | Like 'digit', but throws an 'ErrorCall' if the value is
+-- out of range.
+-- 
+-- sample usage:
+-- 
+-- >>> :set -XDataKinds
+-- >>> :set -XTypeApplications
+-- >>> digit' @9 7
+-- 7 (base 9)
+digit' :: KnownNat base => Int -> Digit base
+digit' x = fromMaybe (error "bad value for base") (digit x)
+
+-- get the Sing type fore the base, given some digit
+digitSing :: KnownNat base => Digit base -> Sing base
+digitSing Digit{} =
+    sing
+
+-- | @getBase d@: return the base of the digit @d@
+getBase :: KnownNat base => Digit base -> Int
+getBase d = fromIntegral $ fromSing (digitSing d)
+
+deriving instance Eq (Digit base)
+deriving instance Ord (Digit base)
+
+instance (KnownNat base) => Show (Digit base) where
+  show d = show (getVal d) ++ " (base " ++ show (getBase d) ++ ")"
+
+instance KnownNat base => Enum (Digit base) where
+  toEnum = digit'
+  fromEnum = getVal
+
+instance (KnownNat base) => Bounded (Digit base) where
+  minBound = digit' 0
+
+  maxBound = digit' $ n - 1
+    where
+      n = getBaseT (Proxy :: Proxy base)
+
+-- | Making 'Digit' an instance of 'Num' does not seem
+-- sensible, but it's nevertheless useful to be able to
+-- add and subtract digits, so '<+>' and '<->' are provided
+-- for this.
+--
+-- @a <+> b@: Add @a@ and @b@. Throws an 'ErrorCall' if the
+-- result is out of range.
+(<+>) :: KnownNat base => Digit base -> Digit base -> Digit base
+a <+> b = digit' $ getVal a + getVal b
+
+-- | @a <-> b@: Subtract @b@ from @a@. Throws an 'ErrorCall' if the
+-- result is out of range.
+(<->) :: KnownNat base => Digit base -> Digit base -> Digit base
+a <-> b = digit' $ getVal a - getVal b
+
diff --git a/test/Data/TypedDigitsSpec.hs b/test/Data/TypedDigitsSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Data/TypedDigitsSpec.hs
@@ -0,0 +1,76 @@
+
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE TypeApplications #-}
+
+module Data.TypedDigitsSpec (main, spec) where
+
+
+import Test.Hspec
+import Test.QuickCheck
+
+import Control.Monad
+import Data.Proxy
+
+import Data.TypedDigits
+
+
+--isInverseOf :: Eq a => (a -> b) -> (b -> a) -> a -> Bool
+--isInverseOf f g x =
+--  g (f x) == x
+--
+--
+--
+--sameAs :: Eq b => (a -> b) -> (a -> b) -> a -> Bool
+--sameAs f g x =
+--  f x == g x
+--
+--dflor = D.digits `sameAs` DD.digits 10
+--
+-- `main` is here so that this module can be run from GHCi on its own.  It is
+-- not needed for automatic spec discovery.
+main :: IO ()
+main = hspec spec
+--
+--digitsImpls :: [(String, Int -> [Int])]
+--digitsImpls = [
+--    ("digits",      D.digits)
+--  , ("digitsIter",  D.digitsIter)
+--  , ("digitsPFree", D.digitsPFree)
+--  ]
+
+-- Let's do things in base 12.
+type TestBase1 = 12
+
+testBase1 :: Int
+testBase1 = fromIntegral $ getBaseT (Proxy :: Proxy TestBase1)
+
+-- digits can be added - up to their valid range
+propAddable :: Property
+propAddable =
+  forAll (choose (0, testBase1-1)) $ \x ->
+    let y = testBase1 - x - 1
+        
+        xd = digit' @TestBase1 x
+        yd = digit' @TestBase1 y
+    in  getVal (xd <+> yd) == testBase1 - 1
+
+
+spec :: Spec
+spec = do 
+  describe "Digits" $ do
+    it "can be added (up to their valid range)" $
+      property propAddable
+    it "have minBound 0" $ 
+      getVal (minBound :: Digit TestBase1) `shouldBe` 0
+    it "have maxBound = base - 1" $ 
+      getVal (maxBound :: Digit TestBase1) `shouldBe` (testBase1 - 1)
+  describe "digit" $ do
+    it "yields Nothing if passed a negative" $
+      digit @TestBase1 (-1) `shouldBe` Nothing
+    it "yields Nothing if passed the base itself" $
+      digit @TestBase1 testBase1 `shouldBe` Nothing
+    it "yields the corresponding digit if passed anything between" $
+      forM_ [0 .. testBase1 - 1] $ \n -> 
+        let x = digit @TestBase1 n
+        in  fmap getVal x `shouldBe` Just n
+
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
diff --git a/typed-digits.cabal b/typed-digits.cabal
new file mode 100644
--- /dev/null
+++ b/typed-digits.cabal
@@ -0,0 +1,72 @@
+name:           typed-digits
+version:        0.1.0.0
+synopsis:       Digits, indexed by their base at the type level
+description:    Digits, indexed by their base at the type level.
+                .
+                Please see the README, for more details, available on GitHub at <https://github.com/arranstewart/hs-typed-digits#readme>.
+category:       Data
+homepage:       https://github.com/arranstewart/hs-typed-digits#readme
+bug-reports:    https://github.com/arranstewart/hs-typed-digits/issues
+author:         Arran Stewart
+maintainer:     haskell-maintenance@arranstewart.info
+copyright:      2019 Arran Stewart
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+extra-source-files:
+    README.md
+    ChangeLog.md
+cabal-version: >= 1.10
+tested-with: GHC ==8.6.5 || ==8.4.4 || ==8.2.2
+
+source-repository head
+  type: git
+  location: https://github.com/arranstewart/hs-typed-digits
+
+Flag Noisy
+    Description: Enable more compilation warnings
+    Manual: True
+    Default: False
+
+library
+  exposed-modules:
+      Data.TypedDigits
+      Data.TypedDigits.Internal
+  hs-source-dirs:
+      src
+  build-depends:
+      base >=4.7 && <5
+    , nats
+    , singletons >= 2.3
+  default-language: Haskell98
+  if flag(Noisy)
+    ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints
+
+test-suite test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  other-modules:
+      Data.TypedDigitsSpec
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , typed-digits
+    , hspec
+    , hspec-discover
+    , QuickCheck
+  default-language: Haskell98
+
+test-suite doctest
+  type: exitcode-stdio-1.0
+  main-is: Main.hs
+  hs-source-dirs:
+      doctest
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.7 && <5
+    , typed-digits
+    , doctest
+    , Glob
+  default-language: Haskell98
