diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,35 @@
+# Changelog for horizon-spec
+
+## v0.2.1
+
+* Update cabal information.
+* Drop down from GHC2021 -> Haskell2010 for hackage.
+
+## v0.2
+
+* Export `Overlay` and `PackageList`.
+* `PackageSet now contains a `PackageList`
+
+## v0.1
+
+* Add dhall types `Name`, `Version`, `Revision`, `Subdir`, `Url'.
+* `GitSource.revision` is no longer `Optional`.
+* Add 'Modifiers.enableProfiling` option with default `True`.
+
+## v0.0.0.3
+
+* Rename `HsSrc` to `HaskellSource`
+* Rename `HsPkg` to `HaskellPackage`
+* Add `Compiler`.
+* Add `PackageSet{compiler, packages}`.
+
+## v0.0.0.2
+
+* Add `CabalFlag`.
+* Add `flags :: [CabalFlag]` to `HsPkg`.
+
+## v0.0.0.1
+
+* Initial Specification of Horizon data types.
+* Two different sources, `GitSource` and `HackageSource`.
+* `doJailbreak` and `doCheck` package `Modifiers`.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright 2022 Homotopic.Tech Ltd
+
+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,19 @@
+# horizon-spec
+
+horizon-spec contains the type definitions for
+[horizon-platform](https://horizon-haskell.net).
+
+Both haskell and dhall versions are supplied.
+
+## Building
+
+```
+nix build
+```
+
+## Development
+
+```
+nix develop
+cabal test all
+```
diff --git a/dhall/package.dhall b/dhall/package.dhall
new file mode 100644
--- /dev/null
+++ b/dhall/package.dhall
@@ -0,0 +1,112 @@
+let Prelude =
+        env:DHALL_PRELUDE
+      ? https://raw.githubusercontent.com/dhall-lang/dhall-lang/v21.1.0/Prelude/package.dhall
+          sha256:0fed19a88330e9a8a3fbe1e8442aa11d12e38da51eb12ba8bcb56f3c25d0854a
+
+let Name = Text
+
+let Version = Text
+
+let Revision = Text
+
+let Subdir = Text
+
+let Url = Text
+
+let HaskellSource =
+      < FromHackage : { name : Name, version : Version }
+      | FromGit : { url : Url, revision : Revision, subdir : Optional Subdir }
+      >
+
+let Modifiers =
+      { Type = { doJailbreak : Bool, doCheck : Bool, enableProfiling : Bool }
+      , default =
+        { doJailbreak = True, doCheck = False, enableProfiling = True }
+      }
+
+let Attr = λ(a : Type) → { mapKey : Text, mapValue : a }
+
+let Flag
+    : ∀(x : Type) → Type
+    = λ(x : Type) → < Enable : x | Disable : x >
+
+let CabalFlag = Flag Text
+
+let HaskellPackage =
+      { Type =
+          { source : HaskellSource
+          , modifiers : Modifiers.Type
+          , flags : List CabalFlag
+          }
+      , default = { modifiers = Modifiers.default, flags = [] : List CabalFlag }
+      }
+
+let Compiler = Text
+
+let PackageEntry = Attr HaskellPackage.Type
+
+let PackageList = List PackageEntry
+
+let PackageSet = { compiler : Compiler, packages : PackageList }
+
+let Overlay = PackageList
+
+let callHackage
+    : Name → Version → Attr HaskellPackage.Type
+    = λ(name : Name) →
+      λ(version : Version) →
+        { mapKey = name
+        , mapValue = HaskellPackage::{
+          , source = HaskellSource.FromHackage { name, version }
+          }
+        }
+
+let callCabal2nix
+    : Name → Url → Revision → Optional Subdir → Attr HaskellPackage.Type
+    = λ(name : Name) →
+      λ(url : Url) →
+      λ(revision : Revision) →
+      λ(subdir : Optional Subdir) →
+        { mapKey = name
+        , mapValue = HaskellPackage::{
+          , source = HaskellSource.FromGit { url, revision, subdir }
+          }
+        }
+
+let modPackageList
+    : Modifiers.Type → PackageList → PackageList
+    = λ(xs : Modifiers.Type) →
+      λ(ps : PackageList) →
+        Prelude.List.map
+          PackageEntry
+          PackageEntry
+          (λ(x : PackageEntry) → x with mapValue.modifiers = xs)
+          ps
+
+let modPackageSet
+    : Modifiers.Type → PackageSet → PackageSet
+    = λ(xs : Modifiers.Type) →
+      λ(ps : PackageSet) →
+        ps
+        with packages = modPackageList xs ps.packages
+
+in  { Attr
+    , CabalFlag
+    , Compiler
+    , Flag
+    , HaskellSource
+    , HaskellPackage
+    , Modifiers
+    , Name
+    , Overlay
+    , PackageList
+    , PackageSet
+    , Revision
+    , Subdir
+    , Version
+    , Url
+    , callCabal2nix
+    , callHackage
+    , modPackageList
+    , modPackageSet
+    }
diff --git a/horizon-spec.cabal b/horizon-spec.cabal
new file mode 100644
--- /dev/null
+++ b/horizon-spec.cabal
@@ -0,0 +1,78 @@
+cabal-version:      3.0
+name:               horizon-spec
+version:            0.2.1
+synopsis:           Horizon Stable Package Set Type Definitions
+description:
+  This package contains the type definitions for the Horizon stable package set (https://horizon-haskell.net). This is a schema used to define package sets sourcing from hackage and git.
+
+category:           Package Management
+author:             Daniel Firth
+maintainer:         dan.firth@homotopic.tech
+copyright:          2022 Daniel Firth
+homepage:           https://horizon-haskell.net
+license:            MIT
+license-file:       LICENSE
+build-type:         Simple
+extra-source-files:
+  ChangeLog.md
+  dhall/package.dhall
+  README.md
+  test/data/modified-overlay/input.dhall
+  test/data/modified-overlay/output.golden
+  test/data/modified-package-set/input.dhall
+  test/data/modified-package-set/output.golden
+  test/data/sample-overlay/input.dhall
+  test/data/sample-overlay/output.golden
+  test/data/sample-package-set/input.dhall
+  test/data/sample-package-set/output.golden
+
+source-repository head
+  type:     git
+  location: https://gitlab.homotopic.tech/horizon/horizon-spec
+
+library
+  exposed-modules:    Horizon.Spec
+  hs-source-dirs:     src
+  default-extensions:
+    DataKinds
+    DeriveGeneric
+    DerivingStrategies
+    GADTs
+    GeneralizedNewtypeDeriving
+    StandaloneKindSignatures
+
+  ghc-options:
+    -Weverything -Wno-all-missed-specialisations -Wno-implicit-prelude
+    -Wno-missing-safe-haskell-mode -Wno-prepositive-qualified-module
+    -Wno-safe -Wno-unsafe
+
+  build-depends:
+    , base                 >=4.7 && <5
+    , containers
+    , dhall
+    , path
+    , path-dhall-instance
+    , text
+
+  default-language:   Haskell2010
+
+executable horizon-spec-tests
+  main-is:            Spec.hs
+  hs-source-dirs:     test
+  ghc-options:
+    -Weverything -Wno-all-missed-specialisations -Wno-implicit-prelude
+    -Wno-missing-safe-haskell-mode -Wno-prepositive-qualified-module
+    -Wno-safe -Wno-unsafe
+
+  default-extensions: TypeApplications
+  build-depends:
+    , base           >=4.7 && <5
+    , bytestring
+    , dhall
+    , horizon-spec
+    , prettyprinter
+    , tasty
+    , tasty-golden
+    , text
+
+  default-language:   Haskell2010
diff --git a/src/Horizon/Spec.hs b/src/Horizon/Spec.hs
new file mode 100644
--- /dev/null
+++ b/src/Horizon/Spec.hs
@@ -0,0 +1,114 @@
+{-# LANGUAGE DeriveAnyClass #-}
+module Horizon.Spec where
+
+import           Data.Kind  (Type)
+import           Data.Map   (Map)
+import           Data.Text  (Text)
+import           Dhall      (FromDhall, Generic, ToDhall)
+import           Path       (Dir, Path, Rel)
+import           Path.Dhall ()
+
+
+type Url :: Type
+newtype Url = MkUrl { fromUrl :: Text }
+  deriving stock (Eq, Show)
+  deriving newtype (FromDhall, ToDhall)
+
+type Repo :: Type
+newtype Repo = MkRepo { fromRepo :: Url }
+  deriving stock (Eq, Show)
+  deriving newtype (FromDhall, ToDhall)
+
+type Subdir :: Type
+newtype Subdir = MkSubdir { fromSubdir :: Path Rel Dir }
+  deriving stock (Eq, Show)
+  deriving newtype (FromDhall, ToDhall)
+
+type Name :: Type
+newtype Name = MkName { fromName :: Text }
+  deriving stock (Eq, Ord, Show)
+  deriving newtype (FromDhall, ToDhall)
+
+type Version :: Type
+newtype Version = MkVersion { fromVersion :: Text }
+  deriving stock (Eq, Show)
+  deriving newtype (FromDhall, ToDhall)
+
+type GitSource :: Type
+data GitSource where
+  MkGitSource :: { url :: Repo, revision :: Revision, subdir :: Maybe Subdir } -> GitSource
+  deriving stock (Eq, Show, Generic)
+  deriving anyclass (FromDhall, ToDhall)
+
+type HackageSource :: Type
+data HackageSource where
+  MkHackageSource :: { name :: Name, version :: Version } -> HackageSource
+  deriving stock (Eq, Show, Generic)
+  deriving anyclass (FromDhall, ToDhall)
+
+type HaskellSource :: Type
+data HaskellSource where
+  FromGit :: GitSource -> HaskellSource
+  FromHackage :: HackageSource -> HaskellSource
+  deriving stock (Show, Eq, Generic)
+  deriving anyclass (FromDhall, ToDhall)
+
+type Flag :: Type -> Type
+data Flag a where
+  Enable :: a -> Flag a
+  Disable :: a -> Flag a
+  deriving stock (Show, Eq, Generic)
+  deriving anyclass (FromDhall, ToDhall)
+
+type CabalFlag :: Type
+data CabalFlag where
+  MkCabalFlag :: Flag Text -> CabalFlag
+  deriving stock (Show, Eq, Generic)
+  deriving anyclass (FromDhall, ToDhall)
+
+type Modifiers :: Type
+data Modifiers where
+  MkModifiers :: { doJailbreak :: Bool
+                 , doCheck :: Bool
+                 , enableProfiling :: Bool } -> Modifiers
+  deriving stock (Show, Eq, Generic)
+  deriving anyclass (FromDhall, ToDhall)
+
+type HaskellPackage :: Type
+data HaskellPackage where
+  MkHaskellPackage :: { source :: HaskellSource
+                      , modifiers :: Modifiers
+                      , flags :: [CabalFlag] } -> HaskellPackage
+  deriving stock (Show, Eq, Generic)
+  deriving anyclass (FromDhall, ToDhall)
+
+type Revision :: Type
+newtype Revision where
+  MkRevision :: { fromRevision :: Text } -> Revision
+  deriving stock (Show, Eq, Generic)
+  deriving newtype (FromDhall, ToDhall)
+
+type Compiler :: Type
+newtype Compiler where
+  MkCompiler :: { fromCompiler :: Text } -> Compiler
+  deriving stock (Show, Eq, Generic)
+  deriving newtype (FromDhall, ToDhall)
+
+type PackageList :: Type
+newtype PackageList where
+  MkPackageList :: { fromPackageList :: Map Name HaskellPackage } -> PackageList
+  deriving stock (Show, Eq, Generic)
+  deriving newtype (FromDhall, ToDhall)
+
+type Overlay :: Type
+newtype Overlay where
+  MkOverlay :: { fromOverlay :: PackageList } -> Overlay
+  deriving stock (Show, Eq, Generic)
+  deriving newtype (FromDhall, ToDhall)
+
+type PackageSet :: Type
+data PackageSet where
+  MkPackageSet :: { compiler :: Compiler
+                  , packages :: PackageList } -> PackageSet
+  deriving stock (Show, Eq, Generic)
+  deriving anyclass (FromDhall, ToDhall)
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,46 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main ( main ) where
+
+import           Data.ByteString           (fromStrict)
+import           Data.Text.Encoding        (encodeUtf8)
+import           Dhall                     (auto, embed, inject, input)
+import           Dhall.Pretty              (layout, prettyExpr)
+import           Horizon.Spec              (Overlay, PackageSet)
+import           Prettyprinter.Render.Text (renderStrict)
+import           Test.Tasty                (TestTree, defaultMain, testGroup)
+import           Test.Tasty.Golden         (goldenVsString)
+
+main :: IO ()
+main = defaultMain tests
+
+tests :: TestTree
+tests = testGroup "Tests"
+          [ samplePackageSet
+          , modifiedPackageSet
+          , sampleOverlay
+          , modifiedOverlay
+          ]
+
+samplePackageSet :: TestTree
+samplePackageSet = goldenVsString "sample package set" "./test/data/sample-package-set/output.golden" $ do
+                    x <- input @PackageSet auto "./test/data/sample-package-set/input.dhall"
+                    let doc = prettyExpr $ embed inject x
+                    pure $ fromStrict $ encodeUtf8 $ renderStrict (layout doc)
+
+modifiedPackageSet :: TestTree
+modifiedPackageSet = goldenVsString "modified package set" "./test/data/modified-package-set/output.golden" $ do
+                    x <- input @PackageSet auto "./test/data/modified-package-set/input.dhall"
+                    let doc = prettyExpr $ embed inject x
+                    pure $ fromStrict $ encodeUtf8 $ renderStrict (layout doc)
+
+sampleOverlay :: TestTree
+sampleOverlay = goldenVsString "sample overlay" "./test/data/sample-overlay/output.golden" $ do
+                    x <- input @Overlay auto "./test/data/sample-overlay/input.dhall"
+                    let doc = prettyExpr $ embed inject x
+                    pure $ fromStrict $ encodeUtf8 $ renderStrict (layout doc)
+
+modifiedOverlay :: TestTree
+modifiedOverlay = goldenVsString "modified overlay" "./test/data/modified-overlay/output.golden" $ do
+                    x <- input @Overlay auto "./test/data/modified-overlay/input.dhall"
+                    let doc = prettyExpr $ embed inject x
+                    pure $ fromStrict $ encodeUtf8 $ renderStrict (layout doc)
diff --git a/test/data/modified-overlay/input.dhall b/test/data/modified-overlay/input.dhall
new file mode 100644
--- /dev/null
+++ b/test/data/modified-overlay/input.dhall
@@ -0,0 +1,12 @@
+let H = ../../../dhall/package.dhall
+
+in    H.modPackageList
+        H.Modifiers::{ doCheck = True, doJailbreak = False }
+        [ H.callHackage "lens" "5.2"
+        , H.callCabal2nix
+            "Cabal-syntax"
+            "https://gitlab.haskell.org/ghc/packages/Cabal"
+            "e714824c6e652bf894f914bc57feccc15759668a"
+            (Some "Cabal-syntax")
+        ]
+    : H.Overlay
diff --git a/test/data/modified-overlay/output.golden b/test/data/modified-overlay/output.golden
new file mode 100644
--- /dev/null
+++ b/test/data/modified-overlay/output.golden
@@ -0,0 +1,28 @@
+[ { mapKey = "Cabal-syntax"
+  , mapValue =
+    { source =
+        < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+        | FromHackage : { name : Text, version : Text }
+        >.FromGit
+          { url = "https://gitlab.haskell.org/ghc/packages/Cabal"
+          , revision = "e714824c6e652bf894f914bc57feccc15759668a"
+          , subdir = Some "Cabal-syntax/"
+          }
+    , modifiers =
+      { doJailbreak = False, doCheck = True, enableProfiling = True }
+    , flags = [] : List < Enable : Text | Disable : Text >
+    }
+  }
+, { mapKey = "lens"
+  , mapValue =
+    { source =
+        < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+        | FromHackage : { name : Text, version : Text }
+        >.FromHackage
+          { name = "lens", version = "5.2" }
+    , modifiers =
+      { doJailbreak = False, doCheck = True, enableProfiling = True }
+    , flags = [] : List < Enable : Text | Disable : Text >
+    }
+  }
+]
diff --git a/test/data/modified-package-set/input.dhall b/test/data/modified-package-set/input.dhall
new file mode 100644
--- /dev/null
+++ b/test/data/modified-package-set/input.dhall
@@ -0,0 +1,15 @@
+let H = ../../../dhall/package.dhall
+
+in    H.modPackageSet
+        H.Modifiers::{ doCheck = True, doJailbreak = False }
+        { compiler = "ghc-9.4.2"
+        , packages =
+          [ H.callHackage "lens" "5.2"
+          , H.callCabal2nix
+              "Cabal-syntax"
+              "https://gitlab.haskell.org/ghc/packages/Cabal"
+              "e714824c6e652bf894f914bc57feccc15759668a"
+              (Some "Cabal-syntax")
+          ]
+        }
+    : H.PackageSet
diff --git a/test/data/modified-package-set/output.golden b/test/data/modified-package-set/output.golden
new file mode 100644
--- /dev/null
+++ b/test/data/modified-package-set/output.golden
@@ -0,0 +1,31 @@
+{ compiler = "ghc-9.4.2"
+, packages =
+  [ { mapKey = "Cabal-syntax"
+    , mapValue =
+      { source =
+          < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+          | FromHackage : { name : Text, version : Text }
+          >.FromGit
+            { url = "https://gitlab.haskell.org/ghc/packages/Cabal"
+            , revision = "e714824c6e652bf894f914bc57feccc15759668a"
+            , subdir = Some "Cabal-syntax/"
+            }
+      , modifiers =
+        { doJailbreak = False, doCheck = True, enableProfiling = True }
+      , flags = [] : List < Enable : Text | Disable : Text >
+      }
+    }
+  , { mapKey = "lens"
+    , mapValue =
+      { source =
+          < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+          | FromHackage : { name : Text, version : Text }
+          >.FromHackage
+            { name = "lens", version = "5.2" }
+      , modifiers =
+        { doJailbreak = False, doCheck = True, enableProfiling = True }
+      , flags = [] : List < Enable : Text | Disable : Text >
+      }
+    }
+  ]
+}
diff --git a/test/data/sample-overlay/input.dhall b/test/data/sample-overlay/input.dhall
new file mode 100644
--- /dev/null
+++ b/test/data/sample-overlay/input.dhall
@@ -0,0 +1,10 @@
+let H = ../../../dhall/package.dhall
+
+in    [ H.callHackage "lens" "5.2"
+      , H.callCabal2nix
+          "Cabal-syntax"
+          "https://gitlab.haskell.org/ghc/packages/Cabal"
+          "e714824c6e652bf894f914bc57feccc15759668a"
+          (Some "Cabal-syntax")
+      ]
+    : H.Overlay
diff --git a/test/data/sample-overlay/output.golden b/test/data/sample-overlay/output.golden
new file mode 100644
--- /dev/null
+++ b/test/data/sample-overlay/output.golden
@@ -0,0 +1,28 @@
+[ { mapKey = "Cabal-syntax"
+  , mapValue =
+    { source =
+        < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+        | FromHackage : { name : Text, version : Text }
+        >.FromGit
+          { url = "https://gitlab.haskell.org/ghc/packages/Cabal"
+          , revision = "e714824c6e652bf894f914bc57feccc15759668a"
+          , subdir = Some "Cabal-syntax/"
+          }
+    , modifiers =
+      { doJailbreak = True, doCheck = False, enableProfiling = True }
+    , flags = [] : List < Enable : Text | Disable : Text >
+    }
+  }
+, { mapKey = "lens"
+  , mapValue =
+    { source =
+        < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+        | FromHackage : { name : Text, version : Text }
+        >.FromHackage
+          { name = "lens", version = "5.2" }
+    , modifiers =
+      { doJailbreak = True, doCheck = False, enableProfiling = True }
+    , flags = [] : List < Enable : Text | Disable : Text >
+    }
+  }
+]
diff --git a/test/data/sample-package-set/input.dhall b/test/data/sample-package-set/input.dhall
new file mode 100644
--- /dev/null
+++ b/test/data/sample-package-set/input.dhall
@@ -0,0 +1,13 @@
+let H = ../../../dhall/package.dhall
+
+in    { compiler = "ghc-9.4.2"
+      , packages =
+        [ H.callHackage "lens" "5.2"
+        , H.callCabal2nix
+            "Cabal-syntax"
+            "https://gitlab.haskell.org/ghc/packages/Cabal"
+            "e714824c6e652bf894f914bc57feccc15759668a"
+            (Some "Cabal-syntax")
+        ]
+      }
+    : H.PackageSet
diff --git a/test/data/sample-package-set/output.golden b/test/data/sample-package-set/output.golden
new file mode 100644
--- /dev/null
+++ b/test/data/sample-package-set/output.golden
@@ -0,0 +1,31 @@
+{ compiler = "ghc-9.4.2"
+, packages =
+  [ { mapKey = "Cabal-syntax"
+    , mapValue =
+      { source =
+          < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+          | FromHackage : { name : Text, version : Text }
+          >.FromGit
+            { url = "https://gitlab.haskell.org/ghc/packages/Cabal"
+            , revision = "e714824c6e652bf894f914bc57feccc15759668a"
+            , subdir = Some "Cabal-syntax/"
+            }
+      , modifiers =
+        { doJailbreak = True, doCheck = False, enableProfiling = True }
+      , flags = [] : List < Enable : Text | Disable : Text >
+      }
+    }
+  , { mapKey = "lens"
+    , mapValue =
+      { source =
+          < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+          | FromHackage : { name : Text, version : Text }
+          >.FromHackage
+            { name = "lens", version = "5.2" }
+      , modifiers =
+        { doJailbreak = True, doCheck = False, enableProfiling = True }
+      , flags = [] : List < Enable : Text | Disable : Text >
+      }
+    }
+  ]
+}
