diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,11 @@
 # Changelog for horizon-spec
 
+## v0.3.0
+
+* Add `LocalSource` and `TarballSource` types
+* Add `FromLocal` and `FromTarball` constructors to `HaskellSource`.
+* rename `callCabal2nix to `callGit`.
+
 ## v0.2.1
 
 * Update cabal information.
diff --git a/dhall/package.dhall b/dhall/package.dhall
--- a/dhall/package.dhall
+++ b/dhall/package.dhall
@@ -16,6 +16,8 @@
 let HaskellSource =
       < FromHackage : { name : Name, version : Version }
       | FromGit : { url : Url, revision : Revision, subdir : Optional Subdir }
+      | FromLocal : Subdir
+      | FromTarball : Url
       >
 
 let Modifiers =
@@ -61,7 +63,7 @@
           }
         }
 
-let callCabal2nix
+let callGit
     : Name → Url → Revision → Optional Subdir → Attr HaskellPackage.Type
     = λ(name : Name) →
       λ(url : Url) →
@@ -73,6 +75,22 @@
           }
         }
 
+let callLocal
+    : Name → Subdir → Attr HaskellPackage.Type
+    = λ(name : Name) →
+      λ(subdir : Subdir) →
+        { mapKey = name
+        , mapValue = HaskellPackage::{ source = HaskellSource.FromLocal subdir }
+        }
+
+let callTarball
+    : Name → Url → Attr HaskellPackage.Type
+    = λ(name : Name) →
+      λ(url : Url) →
+        { mapKey = name
+        , mapValue = HaskellPackage::{ source = HaskellSource.FromTarball url }
+        }
+
 let modPackageList
     : Modifiers.Type → PackageList → PackageList
     = λ(xs : Modifiers.Type) →
@@ -105,8 +123,10 @@
     , Subdir
     , Version
     , Url
-    , callCabal2nix
+    , callGit
     , callHackage
+    , callLocal
+    , callTarball
     , modPackageList
     , modPackageSet
     }
diff --git a/horizon-spec.cabal b/horizon-spec.cabal
--- a/horizon-spec.cabal
+++ b/horizon-spec.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               horizon-spec
-version:            0.2.1
+version:            0.3.0
 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.
@@ -67,12 +67,10 @@
   default-extensions: TypeApplications
   build-depends:
     , base           >=4.7 && <5
-    , bytestring
     , dhall
     , horizon-spec
     , prettyprinter
-    , tasty
-    , tasty-golden
+    , sydtest
     , text
 
   default-language:   Haskell2010
diff --git a/src/Horizon/Spec.hs b/src/Horizon/Spec.hs
--- a/src/Horizon/Spec.hs
+++ b/src/Horizon/Spec.hs
@@ -1,5 +1,26 @@
 {-# LANGUAGE DeriveAnyClass #-}
-module Horizon.Spec where
+module Horizon.Spec
+  ( Url(MkUrl, fromUrl)
+  , Repo(MkRepo, fromRepo)
+  , Subdir(MkSubdir, fromSubdir)
+  , Name(MkName, fromName)
+  , Version (MkVersion, fromVersion)
+  , GitSource(MkGitSource, url, revision, subdir)
+  , HackageSource(MkHackageSource, name, version)
+  , LocalSource(MkLocalSource, fromLocalSource)
+  , TarballSource(MkTarballSource, fromTarballSource)
+  , HaskellSource(FromGit, FromHackage, FromTarball, FromLocal)
+  , Flag(Enable, Disable)
+  , CabalFlag(MkCabalFlag)
+  , Modifiers(doJailbreak, doCheck, enableProfiling)
+  , HaskellPackage(MkHaskellPackage, source, modifiers, flags)
+  , Revision(MkRevision, fromRevision)
+  , Compiler(MkCompiler, fromCompiler)
+  , PackageList(MkPackageList, fromPackageList)
+  , Overlay(MkOverlay, fromOverlay)
+  , PackageSet(MkPackageSet, compiler, packages)
+  )
+  where
 
 import           Data.Kind  (Type)
 import           Data.Map   (Map)
@@ -46,10 +67,24 @@
   deriving stock (Eq, Show, Generic)
   deriving anyclass (FromDhall, ToDhall)
 
+type LocalSource :: Type
+newtype LocalSource where
+  MkLocalSource :: { fromLocalSource :: Subdir } -> LocalSource
+  deriving stock (Eq, Show, Generic)
+  deriving newtype (FromDhall, ToDhall)
+
+type TarballSource :: Type
+newtype TarballSource where
+  MkTarballSource :: { fromTarballSource :: Url } -> TarballSource
+  deriving stock (Eq, Show, Generic)
+  deriving newtype (FromDhall, ToDhall)
+
 type HaskellSource :: Type
 data HaskellSource where
   FromGit :: GitSource -> HaskellSource
   FromHackage :: HackageSource -> HaskellSource
+  FromLocal :: LocalSource -> HaskellSource
+  FromTarball :: TarballSource -> HaskellSource
   deriving stock (Show, Eq, Generic)
   deriving anyclass (FromDhall, ToDhall)
 
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -1,46 +1,37 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE RankNTypes          #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 module Main ( main ) where
 
-import           Data.ByteString           (fromStrict)
+import           Data.Proxy                (Proxy (Proxy))
 import           Data.Text.Encoding        (encodeUtf8)
-import           Dhall                     (auto, embed, inject, input)
+import           Dhall                     (FromDhall, ToDhall, auto, embed,
+                                            inject, inputFile)
 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)
+import           Test.Syd                  (Spec, describe,
+                                            doNotRandomiseExecutionOrder, it,
+                                            pureGoldenByteStringFile,
+                                            sequential, sydTest)
 
-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)
+expectedOutputTest
+  :: forall a.
+     FromDhall a
+  => ToDhall a
+  => Proxy a
+  -> FilePath
+  -> Spec
+expectedOutputTest _ n = describe n $ do
+  it "expands correctly" $ do
+    x <- inputFile @a auto $ "test/data/" ++ n ++ "/input.dhall"
+    let doc = prettyExpr $ embed inject x
+    let docstr = encodeUtf8 $ renderStrict $ layout doc
+    pure $ pureGoldenByteStringFile ("test/data/" ++ n ++ "/output.golden") docstr
 
-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)
+main :: IO ()
+main = sydTest $ doNotRandomiseExecutionOrder $ sequential $ do
+  expectedOutputTest (Proxy @PackageSet) "sample-package-set"
+  expectedOutputTest (Proxy @PackageSet) "modified-package-set"
+  expectedOutputTest (Proxy @Overlay) "sample-overlay"
+  expectedOutputTest (Proxy @Overlay) "modified-overlay"
diff --git a/test/data/modified-overlay/input.dhall b/test/data/modified-overlay/input.dhall
--- a/test/data/modified-overlay/input.dhall
+++ b/test/data/modified-overlay/input.dhall
@@ -3,10 +3,14 @@
 in    H.modPackageList
         H.Modifiers::{ doCheck = True, doJailbreak = False }
         [ H.callHackage "lens" "5.2"
-        , H.callCabal2nix
+        , H.callGit
             "Cabal-syntax"
             "https://gitlab.haskell.org/ghc/packages/Cabal"
             "e714824c6e652bf894f914bc57feccc15759668a"
             (Some "Cabal-syntax")
+        , H.callTarball
+            "network-mux"
+            "https://input-output-hk.github.io/cardano-haskell-packages/package/network-mux-0.2.0.0.tar.gz"
+        , H.callLocal "myPackage" "./myPackage"
         ]
     : H.Overlay
diff --git a/test/data/modified-overlay/output.golden b/test/data/modified-overlay/output.golden
--- a/test/data/modified-overlay/output.golden
+++ b/test/data/modified-overlay/output.golden
@@ -3,6 +3,8 @@
     { source =
         < FromGit : { url : Text, revision : Text, subdir : Optional Text }
         | FromHackage : { name : Text, version : Text }
+        | FromLocal : Text
+        | FromTarball : Text
         >.FromGit
           { url = "https://gitlab.haskell.org/ghc/packages/Cabal"
           , revision = "e714824c6e652bf894f914bc57feccc15759668a"
@@ -18,8 +20,38 @@
     { source =
         < FromGit : { url : Text, revision : Text, subdir : Optional Text }
         | FromHackage : { name : Text, version : Text }
+        | FromLocal : Text
+        | FromTarball : Text
         >.FromHackage
           { name = "lens", version = "5.2" }
+    , modifiers =
+      { doJailbreak = False, doCheck = True, enableProfiling = True }
+    , flags = [] : List < Enable : Text | Disable : Text >
+    }
+  }
+, { mapKey = "myPackage"
+  , mapValue =
+    { source =
+        < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+        | FromHackage : { name : Text, version : Text }
+        | FromLocal : Text
+        | FromTarball : Text
+        >.FromLocal
+          "myPackage/"
+    , modifiers =
+      { doJailbreak = False, doCheck = True, enableProfiling = True }
+    , flags = [] : List < Enable : Text | Disable : Text >
+    }
+  }
+, { mapKey = "network-mux"
+  , mapValue =
+    { source =
+        < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+        | FromHackage : { name : Text, version : Text }
+        | FromLocal : Text
+        | FromTarball : Text
+        >.FromTarball
+          "https://input-output-hk.github.io/cardano-haskell-packages/package/network-mux-0.2.0.0.tar.gz"
     , 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
--- a/test/data/modified-package-set/input.dhall
+++ b/test/data/modified-package-set/input.dhall
@@ -5,11 +5,15 @@
         { compiler = "ghc-9.4.2"
         , packages =
           [ H.callHackage "lens" "5.2"
-          , H.callCabal2nix
+          , H.callGit
               "Cabal-syntax"
               "https://gitlab.haskell.org/ghc/packages/Cabal"
               "e714824c6e652bf894f914bc57feccc15759668a"
               (Some "Cabal-syntax")
+          , H.callTarball
+              "network-mux"
+              "https://input-output-hk.github.io/cardano-haskell-packages/package/network-mux-0.2.0.0.tar.gz"
+          , H.callLocal "myPackage" "./myPackage"
           ]
         }
     : H.PackageSet
diff --git a/test/data/modified-package-set/output.golden b/test/data/modified-package-set/output.golden
--- a/test/data/modified-package-set/output.golden
+++ b/test/data/modified-package-set/output.golden
@@ -5,6 +5,8 @@
       { source =
           < FromGit : { url : Text, revision : Text, subdir : Optional Text }
           | FromHackage : { name : Text, version : Text }
+          | FromLocal : Text
+          | FromTarball : Text
           >.FromGit
             { url = "https://gitlab.haskell.org/ghc/packages/Cabal"
             , revision = "e714824c6e652bf894f914bc57feccc15759668a"
@@ -20,8 +22,38 @@
       { source =
           < FromGit : { url : Text, revision : Text, subdir : Optional Text }
           | FromHackage : { name : Text, version : Text }
+          | FromLocal : Text
+          | FromTarball : Text
           >.FromHackage
             { name = "lens", version = "5.2" }
+      , modifiers =
+        { doJailbreak = False, doCheck = True, enableProfiling = True }
+      , flags = [] : List < Enable : Text | Disable : Text >
+      }
+    }
+  , { mapKey = "myPackage"
+    , mapValue =
+      { source =
+          < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+          | FromHackage : { name : Text, version : Text }
+          | FromLocal : Text
+          | FromTarball : Text
+          >.FromLocal
+            "myPackage/"
+      , modifiers =
+        { doJailbreak = False, doCheck = True, enableProfiling = True }
+      , flags = [] : List < Enable : Text | Disable : Text >
+      }
+    }
+  , { mapKey = "network-mux"
+    , mapValue =
+      { source =
+          < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+          | FromHackage : { name : Text, version : Text }
+          | FromLocal : Text
+          | FromTarball : Text
+          >.FromTarball
+            "https://input-output-hk.github.io/cardano-haskell-packages/package/network-mux-0.2.0.0.tar.gz"
       , 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
--- a/test/data/sample-overlay/input.dhall
+++ b/test/data/sample-overlay/input.dhall
@@ -1,10 +1,14 @@
 let H = ../../../dhall/package.dhall
 
 in    [ H.callHackage "lens" "5.2"
-      , H.callCabal2nix
+      , H.callGit
           "Cabal-syntax"
           "https://gitlab.haskell.org/ghc/packages/Cabal"
           "e714824c6e652bf894f914bc57feccc15759668a"
           (Some "Cabal-syntax")
+      , H.callTarball
+          "network-mux"
+          "https://input-output-hk.github.io/cardano-haskell-packages/package/network-mux-0.2.0.0.tar.gz"
+      , H.callLocal "myPackage" "./myPackage"
       ]
     : H.Overlay
diff --git a/test/data/sample-overlay/output.golden b/test/data/sample-overlay/output.golden
--- a/test/data/sample-overlay/output.golden
+++ b/test/data/sample-overlay/output.golden
@@ -3,6 +3,8 @@
     { source =
         < FromGit : { url : Text, revision : Text, subdir : Optional Text }
         | FromHackage : { name : Text, version : Text }
+        | FromLocal : Text
+        | FromTarball : Text
         >.FromGit
           { url = "https://gitlab.haskell.org/ghc/packages/Cabal"
           , revision = "e714824c6e652bf894f914bc57feccc15759668a"
@@ -18,8 +20,38 @@
     { source =
         < FromGit : { url : Text, revision : Text, subdir : Optional Text }
         | FromHackage : { name : Text, version : Text }
+        | FromLocal : Text
+        | FromTarball : Text
         >.FromHackage
           { name = "lens", version = "5.2" }
+    , modifiers =
+      { doJailbreak = True, doCheck = False, enableProfiling = True }
+    , flags = [] : List < Enable : Text | Disable : Text >
+    }
+  }
+, { mapKey = "myPackage"
+  , mapValue =
+    { source =
+        < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+        | FromHackage : { name : Text, version : Text }
+        | FromLocal : Text
+        | FromTarball : Text
+        >.FromLocal
+          "myPackage/"
+    , modifiers =
+      { doJailbreak = True, doCheck = False, enableProfiling = True }
+    , flags = [] : List < Enable : Text | Disable : Text >
+    }
+  }
+, { mapKey = "network-mux"
+  , mapValue =
+    { source =
+        < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+        | FromHackage : { name : Text, version : Text }
+        | FromLocal : Text
+        | FromTarball : Text
+        >.FromTarball
+          "https://input-output-hk.github.io/cardano-haskell-packages/package/network-mux-0.2.0.0.tar.gz"
     , 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
--- a/test/data/sample-package-set/input.dhall
+++ b/test/data/sample-package-set/input.dhall
@@ -3,11 +3,15 @@
 in    { compiler = "ghc-9.4.2"
       , packages =
         [ H.callHackage "lens" "5.2"
-        , H.callCabal2nix
+        , H.callGit
             "Cabal-syntax"
             "https://gitlab.haskell.org/ghc/packages/Cabal"
             "e714824c6e652bf894f914bc57feccc15759668a"
             (Some "Cabal-syntax")
+        , H.callTarball
+            "network-mux"
+            "https://input-output-hk.github.io/cardano-haskell-packages/package/network-mux-0.2.0.0.tar.gz"
+        , H.callLocal "myPackage" "./myPackage"
         ]
       }
     : H.PackageSet
diff --git a/test/data/sample-package-set/output.golden b/test/data/sample-package-set/output.golden
--- a/test/data/sample-package-set/output.golden
+++ b/test/data/sample-package-set/output.golden
@@ -5,6 +5,8 @@
       { source =
           < FromGit : { url : Text, revision : Text, subdir : Optional Text }
           | FromHackage : { name : Text, version : Text }
+          | FromLocal : Text
+          | FromTarball : Text
           >.FromGit
             { url = "https://gitlab.haskell.org/ghc/packages/Cabal"
             , revision = "e714824c6e652bf894f914bc57feccc15759668a"
@@ -20,8 +22,38 @@
       { source =
           < FromGit : { url : Text, revision : Text, subdir : Optional Text }
           | FromHackage : { name : Text, version : Text }
+          | FromLocal : Text
+          | FromTarball : Text
           >.FromHackage
             { name = "lens", version = "5.2" }
+      , modifiers =
+        { doJailbreak = True, doCheck = False, enableProfiling = True }
+      , flags = [] : List < Enable : Text | Disable : Text >
+      }
+    }
+  , { mapKey = "myPackage"
+    , mapValue =
+      { source =
+          < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+          | FromHackage : { name : Text, version : Text }
+          | FromLocal : Text
+          | FromTarball : Text
+          >.FromLocal
+            "myPackage/"
+      , modifiers =
+        { doJailbreak = True, doCheck = False, enableProfiling = True }
+      , flags = [] : List < Enable : Text | Disable : Text >
+      }
+    }
+  , { mapKey = "network-mux"
+    , mapValue =
+      { source =
+          < FromGit : { url : Text, revision : Text, subdir : Optional Text }
+          | FromHackage : { name : Text, version : Text }
+          | FromLocal : Text
+          | FromTarball : Text
+          >.FromTarball
+            "https://input-output-hk.github.io/cardano-haskell-packages/package/network-mux-0.2.0.0.tar.gz"
       , modifiers =
         { doJailbreak = True, doCheck = False, enableProfiling = True }
       , flags = [] : List < Enable : Text | Disable : Text >
