diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,10 @@
 # Changelog for horizon-gen-nix
 
+## v0.3.0
+
+* Support horizon-spec-0.3.0
+* Allow for building from local packages and tarballs.
+
 ## v0.2
 
 * Support horizon-spec-0.2
diff --git a/horizon-gen-nix.cabal b/horizon-gen-nix.cabal
--- a/horizon-gen-nix.cabal
+++ b/horizon-gen-nix.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               horizon-gen-nix
-version:            0.2
+version:            0.3.0
 synopsis:           Generate nix expressions from horizon-spec definitions
 description:        Generate nix expressions from horizon-spec definitions
 category:           Package Management, Nix
@@ -52,7 +52,7 @@
     , directory
     , distribution-nixpkgs
     , either
-    , horizon-spec          >=0.2 && <0.3
+    , horizon-spec          >=0.3 && <0.4
     , language-nix
     , lens
     , optparse-applicative
@@ -80,7 +80,7 @@
     , base             >=4.7 && <5
     , horizon-gen-nix
 
-  default-language:   GHC2021
+  default-language:   Haskell2010
 
 executable horizon-gen-nix-tests
   main-is:          Spec.hs
diff --git a/src/Horizon/Gen/Nix.hs b/src/Horizon/Gen/Nix.hs
--- a/src/Horizon/Gen/Nix.hs
+++ b/src/Horizon/Gen/Nix.hs
@@ -7,12 +7,14 @@
   ) where
 
 import           Dhall                                   (auto, inputFile)
-import           Horizon.Gen.Nix.Options                 (HorizonCommand (MakePackageSetCommand, OverlayCommand),
+import           Horizon.Gen.Nix.Options                 (Force,
+                                                          HorizonCommand (MakePackageSetCommand, OverlayCommand),
                                                           HorizonOptions (MkHorizonOptions),
                                                           MakePackageSetOptions,
                                                           OverlayOptions,
                                                           fromInputFile,
                                                           horizonGenNixOptsInfo,
+                                                          optForce,
                                                           optHorizonCommand,
                                                           optInputFile,
                                                           optOverlayFile,
@@ -29,14 +31,14 @@
 import           Path.Dhall                              ()
 
 
-makeMakePackageSet :: MakePackageSetOptions -> PackagesDirectory -> PackageSet -> IO ()
-makeMakePackageSet opts d xs = do
-  writeHaskellPackages d (packages xs)
+makeMakePackageSet :: Force -> MakePackageSetOptions -> PackagesDirectory -> PackageSet -> IO ()
+makeMakePackageSet f opts d xs = do
+  writeHaskellPackages d f (packages xs)
   writeMakePackageSet d (optPackageSetFile opts) xs
 
-makeOverlay :: OverlayOptions -> PackagesDirectory -> Overlay -> IO ()
-makeOverlay opts d xs = do
-  writeHaskellPackages d (fromOverlay xs)
+makeOverlay :: Force -> OverlayOptions -> PackagesDirectory -> Overlay -> IO ()
+makeOverlay f opts d xs = do
+  writeHaskellPackages d f (fromOverlay xs)
   writeOverlay d (optOverlayFile opts) xs
 
 horizonGenNix :: HorizonOptions -> IO ()
@@ -45,10 +47,10 @@
   in case optHorizonCommand of
     MakePackageSetCommand opts -> do
       x <- inputFile @PackageSet auto fp
-      makeMakePackageSet opts optPackagesDirectory x
+      makeMakePackageSet optForce opts optPackagesDirectory x
     OverlayCommand opts -> do
       x <- inputFile @Overlay auto fp
-      makeOverlay opts optPackagesDirectory x
+      makeOverlay optForce opts optPackagesDirectory x
 
 main :: IO ()
 main = do
diff --git a/src/Horizon/Gen/Nix/Cabal2Nix/Options.hs b/src/Horizon/Gen/Nix/Cabal2Nix/Options.hs
--- a/src/Horizon/Gen/Nix/Cabal2Nix/Options.hs
+++ b/src/Horizon/Gen/Nix/Cabal2Nix/Options.hs
@@ -39,10 +39,13 @@
 import           Horizon.Spec                                   (GitSource (MkGitSource),
                                                                  HackageSource (MkHackageSource),
                                                                  HaskellPackage (MkHaskellPackage),
-                                                                 HaskellSource (FromGit, FromHackage),
+                                                                 HaskellSource (FromGit, FromHackage, FromLocal, FromTarball),
+                                                                 LocalSource (MkLocalSource),
                                                                  Modifiers,
                                                                  Name (MkName),
                                                                  Repo (MkRepo),
+                                                                 Subdir (MkSubdir),
+                                                                 TarballSource (MkTarballSource),
                                                                  Url (MkUrl),
                                                                  Version (MkVersion),
                                                                  doCheck,
@@ -88,6 +91,8 @@
     case x of
       FromHackage z -> applyHackageSourceToCabal2NixOptions z
       FromGit z     -> applyGitSourceToCabal2NixOptions z
+      FromLocal z   -> applyLocalSourceToCabal2NixOptions z
+      FromTarball z -> applyTarballSourceToCabal2NixOptions z
     ) mkDefaultCabal2NixOptions
 
 applyGitSourceToCabal2NixOptions
@@ -104,6 +109,12 @@
 applyHackageSourceToCabal2NixOptions ::  HackageSource -> Options -> Options
 applyHackageSourceToCabal2NixOptions (MkHackageSource (MkName n) (MkVersion v)) opts = opts
   { optUrl = "cabal://" <> T.unpack n <> "-" <> T.unpack v }
+
+applyLocalSourceToCabal2NixOptions :: LocalSource -> Options -> Options
+applyLocalSourceToCabal2NixOptions (MkLocalSource (MkSubdir d)) opts = opts { optUrl = "file://" <> toFilePath d }
+
+applyTarballSourceToCabal2NixOptions :: TarballSource -> Options -> Options
+applyTarballSourceToCabal2NixOptions (MkTarballSource (MkUrl u)) opts = opts { optUrl = T.unpack u }
 
 applyModifiersToCabal2NixOptions :: Modifiers -> Options -> Options
 applyModifiersToCabal2NixOptions ms opts = opts
diff --git a/src/Horizon/Gen/Nix/Options.hs b/src/Horizon/Gen/Nix/Options.hs
--- a/src/Horizon/Gen/Nix/Options.hs
+++ b/src/Horizon/Gen/Nix/Options.hs
@@ -4,6 +4,7 @@
 module Horizon.Gen.Nix.Options
   ( horizonGenNixOpts
   , horizonGenNixOptsInfo
+  , Force(..)
   , InputFile (..)
   , HorizonCommand (..)
   , HorizonOptions (..)
@@ -23,11 +24,11 @@
 import           Horizon.Gen.Nix.Types.PackageSetFile    (PackageSetFile (MkPackageSetFile))
 import           Options.Applicative                     (Parser, ParserInfo,
                                                           ReadM, command,
-                                                          eitherReader, help,
-                                                          helper, info, long,
-                                                          metavar, option,
-                                                          progDesc, subparser,
-                                                          value)
+                                                          eitherReader, flag',
+                                                          help, helper, info,
+                                                          long, metavar, option,
+                                                          progDesc, short,
+                                                          subparser, value)
 import           Path                                    (File, Path, Rel,
                                                           mkRelDir, mkRelFile,
                                                           parseRelDir,
@@ -140,9 +141,20 @@
   OverlayCommand :: OverlayOptions -> HorizonCommand
   deriving stock (Eq, Show)
 
+type Force :: Type
+newtype Force = MkForce Bool
+  deriving stock (Eq, Show)
+
+forceOption :: Parser Force
+forceOption = flag' (MkForce True)
+  (  long "force"
+  <> short 'f'
+  <> help "forcibly regenerate the packages")
+
 type HorizonOptions :: Type
 data HorizonOptions where
-  MkHorizonOptions :: { optInputFile :: InputFile
+  MkHorizonOptions :: { optForce :: Force
+                      , optInputFile :: InputFile
                       , optPackagesDirectory :: PackagesDirectory
                       , optHorizonCommand :: HorizonCommand} -> HorizonOptions
   deriving stock (Eq, Show)
@@ -162,7 +174,8 @@
 horizonGenNixOpts :: Parser HorizonOptions
 horizonGenNixOpts =
       MkHorizonOptions
-  <$> inputFileOption
+  <$> forceOption
+  <*> inputFileOption
   <*> packagesDirectoryOption
   <*> horizonCommandOpts
 
diff --git a/src/Horizon/Gen/Nix/Writers.hs b/src/Horizon/Gen/Nix/Writers.hs
--- a/src/Horizon/Gen/Nix/Writers.hs
+++ b/src/Horizon/Gen/Nix/Writers.hs
@@ -9,11 +9,12 @@
  ) where
 
 import           Cabal2nix                               (Options, cabal2nix')
-import           Control.Monad                           (forM_, unless, (>=>))
+import           Control.Monad                           (forM_, when, (>=>))
 import           Data.Map                                (keys, toList)
 import qualified Data.Text                               as T
 import           Distribution.Nixpkgs.Haskell.Derivation (Derivation)
 import           Horizon.Gen.Nix.Cabal2Nix.Options       (haskellPackageToCabal2NixOptions)
+import           Horizon.Gen.Nix.Options                 (Force (MkForce))
 import           Horizon.Gen.Nix.Pretty                  (prettyDerivation)
 import           Horizon.Gen.Nix.Types.OverlayFile       (OverlayFile (MkOverlayFile))
 import           Horizon.Gen.Nix.Types.PackagesDirectory (PackagesDirectory (MkPackagesDirectory))
@@ -66,14 +67,14 @@
 writeDerivation :: Path b File -> Derivation -> IO ()
 writeDerivation f = writeFile (toFilePath f) . show . prettyDerivation
 
-writeHaskellPackage :: PackagesDirectory -> Name -> HaskellPackage -> IO ()
-writeHaskellPackage (MkPackagesDirectory d) (MkName f) y = do
+writeHaskellPackage :: PackagesDirectory -> Force -> Name -> HaskellPackage -> IO ()
+writeHaskellPackage (MkPackagesDirectory d) (MkForce b) (MkName f) y = do
   let o = haskellPackageToCabal2NixOptions y
   createDirectoryIfMissing True (toFilePath d)
   f' <- parseRelFile  $ T.unpack (f <> ".nix")
   let j = d </> f'
-  q  <- doesFileExist $ toFilePath j
-  unless q $ writeCabal2Nix j o
+  q <- doesFileExist $ toFilePath j
+  when (b || not q) $ writeCabal2Nix j o
 
-writeHaskellPackages :: PackagesDirectory -> PackageList -> IO ()
-writeHaskellPackages d = mapM_ (uncurry $ writeHaskellPackage d) . toList . fromPackageList
+writeHaskellPackages :: PackagesDirectory -> Force -> PackageList -> IO ()
+writeHaskellPackages f d = mapM_ (uncurry $ writeHaskellPackage f d) . toList . fromPackageList
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -3,119 +3,65 @@
 module Main ( main ) where
 
 import           Control.Exception       (bracket_)
+import           Control.Monad           (forM_)
 import           Horizon.Gen.Nix         (horizonGenNix)
-import           Horizon.Gen.Nix.Options (HorizonCommand (MakePackageSetCommand, OverlayCommand),
+import           Horizon.Gen.Nix.Options (Force (MkForce),
+                                          HorizonCommand (MakePackageSetCommand, OverlayCommand),
                                           HorizonOptions (MkHorizonOptions),
                                           InputFile (MkInputFile),
                                           defaultMakePackageSetOptions,
                                           defaultOverlayOptions,
-                                          defaultPackagesDirectory,
+                                          defaultPackagesDirectory, optForce,
                                           optHorizonCommand, optInputFile,
                                           optPackagesDirectory)
-import           Path                    (mkRelFile)
+import           Path                    (File, Path, Rel, mkRelFile,
+                                          parseRelFile, toFilePath)
 import           System.Directory        (removeFile)
 import           Test.Syd                (Spec, aroundAll_, describe,
                                           doNotRandomiseExecutionOrder,
                                           goldenStringFile, it, sequential,
                                           sydTest)
 
-main :: IO ()
-main = sydTest $ doNotRandomiseExecutionOrder $ sequential $ do
-  samplePackageSet
-  modifiedPackageSet
-  sampleOverlay
-  modifiedOverlay
-
-withSamplePackageSet :: IO a -> IO a
-withSamplePackageSet = bracket_ runSamplePackageSet cleanupPackageSet
-
-
-withModifiedPackageSet :: IO a -> IO a
-withModifiedPackageSet = bracket_ runModifiedPackageSet cleanupPackageSet
-
-
-withSampleOverlay :: IO a -> IO a
-withSampleOverlay = bracket_ runSampleOverlay cleanupOverlay
-
-
-withModifiedOverlay :: IO a -> IO a
-withModifiedOverlay = bracket_ runModifiedOverlay cleanupOverlay
-
-
-runSamplePackageSet :: IO ()
-runSamplePackageSet = do
-    let opts = MkHorizonOptions
-                 { optHorizonCommand = MakePackageSetCommand defaultMakePackageSetOptions
-                 , optPackagesDirectory = defaultPackagesDirectory
-                 , optInputFile = MkInputFile $(mkRelFile "test/data/sample-package-set/input.dhall")
-                 }
-    horizonGenNix opts
-
-
-runModifiedPackageSet :: IO ()
-runModifiedPackageSet = do
-    let opts = MkHorizonOptions
-                 { optHorizonCommand = MakePackageSetCommand defaultMakePackageSetOptions
-                 , optPackagesDirectory = defaultPackagesDirectory
-                 , optInputFile = MkInputFile $(mkRelFile "test/data/modified-package-set/input.dhall")
-                 }
-    horizonGenNix opts
-
-runSampleOverlay :: IO ()
-runSampleOverlay = do
-    let opts = MkHorizonOptions
-                 { optHorizonCommand = OverlayCommand defaultOverlayOptions
-                 , optPackagesDirectory = defaultPackagesDirectory
-                 , optInputFile = MkInputFile $(mkRelFile "test/data/sample-overlay/input.dhall")
-                 }
-    horizonGenNix opts
+outputFilesOverlayRel :: [Path Rel File]
+outputFilesOverlayRel =
+  [ $(mkRelFile "overlay.nix")
+  , $(mkRelFile "pkgs/lens.nix")
+  , $(mkRelFile "pkgs/Cabal-syntax.nix")
+  , $(mkRelFile "pkgs/network-mux.nix")
+  , $(mkRelFile "pkgs/myPackage.nix")
+  ]
 
+outputFilesPackageSetRel :: [Path Rel File]
+outputFilesPackageSetRel =
+  [ $(mkRelFile "initial-packages.nix")
+  , $(mkRelFile "pkgs/lens.nix")
+  , $(mkRelFile "pkgs/Cabal-syntax.nix")
+  , $(mkRelFile "pkgs/network-mux.nix")
+  , $(mkRelFile "pkgs/myPackage.nix")
+  ]
 
-runModifiedOverlay :: IO ()
-runModifiedOverlay = do
+runHorizonGenNixFor :: FilePath -> HorizonCommand -> IO ()
+runHorizonGenNixFor s cmd = do
+    fp <- parseRelFile $ "test/data/" ++ s ++ "/input.dhall"
     let opts = MkHorizonOptions
-                 { optHorizonCommand = OverlayCommand defaultOverlayOptions
+                 { optHorizonCommand = cmd
+                 , optForce = MkForce False
                  , optPackagesDirectory = defaultPackagesDirectory
-                 , optInputFile = MkInputFile $(mkRelFile "test/data/modified-overlay/input.dhall")
+                 , optInputFile = MkInputFile fp
                  }
     horizonGenNix opts
 
-cleanupPackageSet :: IO ()
-cleanupPackageSet = mapM_ removeFile ["initial-packages.nix", "pkgs/lens.nix", "pkgs/Cabal-syntax.nix" ]
-
-
-cleanupOverlay :: IO ()
-cleanupOverlay = mapM_ removeFile ["overlay.nix", "pkgs/lens.nix", "pkgs/Cabal-syntax.nix" ]
-
-
-
-samplePackageSet :: Spec
-samplePackageSet = describe "sample package set" $ sequential $
-  aroundAll_ withSamplePackageSet $ do
-    it "initial-packages.nix" $ goldenStringFile "test/data/sample-package-set/output/initial-packages.nix.golden" (readFile "initial-packages.nix")
-    it "pkgs/lens.nix" $ goldenStringFile "test/data/sample-package-set/output/pkgs/lens.nix.golden" (readFile "pkgs/lens.nix")
-    it "pkgs/Cabal-syntax.nix" $ goldenStringFile "test/data/sample-package-set/output/pkgs/Cabal-syntax.nix.golden" (readFile "pkgs/Cabal-syntax.nix")
-
-
-modifiedPackageSet :: Spec
-modifiedPackageSet = describe "modified package set" $ sequential $
-  aroundAll_ withModifiedPackageSet $ do
-    it "initial-packages.nix" $ goldenStringFile "test/data/modified-package-set/output/initial-packages.nix.golden" (readFile "initial-packages.nix")
-    it "pkgs/lens.nix" $ goldenStringFile "test/data/modified-package-set/output/pkgs/lens.nix.golden" (readFile "pkgs/lens.nix")
-    it "pkgs/Cabal-syntax.nix" $ goldenStringFile "test/data/modified-package-set/output/pkgs/Cabal-syntax.nix.golden" (readFile "pkgs/Cabal-syntax.nix")
-
-
-sampleOverlay :: Spec
-sampleOverlay = describe "sample overlay" $ sequential $
-  aroundAll_ withSampleOverlay $ do
-    it "overlay.nix" $ goldenStringFile "test/data/sample-overlay/output/overlay.nix.golden" (readFile "overlay.nix")
-    it "pkgs/lens.nix" $ goldenStringFile "test/data/sample-overlay/output/pkgs/lens.nix.golden" (readFile "pkgs/lens.nix")
-    it "pkgs/Cabal-syntax.nix" $ goldenStringFile "test/data/sample-overlay/output/pkgs/Cabal-syntax.nix.golden" (readFile "pkgs/Cabal-syntax.nix")
-
+expectedOutputTest :: FilePath -> [Path Rel File] -> HorizonCommand -> Spec
+expectedOutputTest s xs cmd = describe s $ sequential $
+  aroundAll_ (bracket_ (runHorizonGenNixFor s cmd) (mapM_ (removeFile . toFilePath) xs)) $ forM_ xs $ \x ->
+    it (toFilePath x) $
+      goldenStringFile
+        ("test/data/" ++ s ++ "/output/" ++ toFilePath x ++ ".golden")
+        (readFile $ toFilePath x)
 
-modifiedOverlay :: Spec
-modifiedOverlay = describe "modified overlay" $ sequential $
-  aroundAll_ withModifiedOverlay $ do
-    it "overlay.nix" $ goldenStringFile "test/data/modified-overlay/output/overlay.nix.golden" (readFile "overlay.nix")
-    it "pkgs/lens.nix" $ goldenStringFile "test/data/modified-overlay/output/pkgs/lens.nix.golden" (readFile "pkgs/lens.nix")
-    it "pkgs/Cabal-syntax.nix" $ goldenStringFile "test/data/modified-overlay/output/pkgs/Cabal-syntax.nix.golden" (readFile "pkgs/Cabal-syntax.nix")
+main :: IO ()
+main = sydTest $ doNotRandomiseExecutionOrder $ sequential $ do
+  expectedOutputTest "sample-package-set" outputFilesPackageSetRel (MakePackageSetCommand defaultMakePackageSetOptions)
+  expectedOutputTest "modified-package-set" outputFilesPackageSetRel (MakePackageSetCommand defaultMakePackageSetOptions)
+  expectedOutputTest "sample-overlay" outputFilesOverlayRel (OverlayCommand defaultOverlayOptions)
+  expectedOutputTest "modified-overlay" outputFilesOverlayRel (OverlayCommand defaultOverlayOptions)
