diff --git a/src/Zifter/Recurse.hs b/src/Zifter/Recurse.hs
--- a/src/Zifter/Recurse.hs
+++ b/src/Zifter/Recurse.hs
@@ -3,13 +3,16 @@
 module Zifter.Recurse
     ( recursiveZift
     , recursively
+    , hiddenIn
     ) where
 
 import Control.Monad
 import Control.Monad.IO.Class
+import Data.List
 import Path
 import Path.IO
 import System.Exit
+import qualified System.FilePath as FP
 import System.IO
 import System.Process
 
@@ -109,19 +112,11 @@
 findZiftFilesRecursively :: Zift [Path Abs File]
 findZiftFilesRecursively = do
     rd <- getRootDir
-    let filterZiftFiles = filter ((== $(mkRelFile "zift.hs")) . filename) -- TODO generalise to given predicate
-    let recurser ad dirs files =
-            if ad == rd
-                then pure $ WalkExclude []
-                else do
-                    let ziftFiles = filterZiftFiles files
-                    case ziftFiles of
-                        [] -> pure $ WalkExclude [] -- No zift files found, recurse further downward.
-                        -- Zift files found, run each of them but don't recurse further. That's their job.
-                        _ -> pure $ WalkExclude dirs
-    let outputWriter ad _ files =
-            pure $
-            if ad == rd
-                then []
-                else filterZiftFiles files
-    walkDirAccum (Just recurser) outputWriter rd
+    fs <- findFiles [rd] $(mkRelFile "zift.hs")
+    pure $ filter (not . hiddenIn rd) fs
+
+hiddenIn :: Path Abs Dir -> Path Abs File -> Bool
+hiddenIn rp af =
+    case stripProperPrefix rp af of
+        Nothing -> True
+        Just rf -> any (isPrefixOf ".") $ FP.splitDirectories $ fromRelFile rf
diff --git a/test/TestImport.hs b/test/TestImport.hs
new file mode 100644
--- /dev/null
+++ b/test/TestImport.hs
@@ -0,0 +1,15 @@
+module TestImport
+    ( module X
+    ) where
+
+import Data.Maybe as X
+import Data.Monoid as X
+
+import Test.Hspec as X
+import Test.QuickCheck as X
+import Test.Validity as X
+
+import Path as X
+import Path.IO as X
+
+import Data.GenValidity.Path ()
diff --git a/test/Zifter/Gen.hs b/test/Zifter/Gen.hs
--- a/test/Zifter/Gen.hs
+++ b/test/Zifter/Gen.hs
@@ -2,7 +2,7 @@
 
 module Zifter.Gen where
 
-import Data.GenValidity
+import TestImport
 
 import Zifter
 import Zifter.Zift.Gen ()
diff --git a/test/Zifter/OptParse/Gen.hs b/test/Zifter/OptParse/Gen.hs
--- a/test/Zifter/OptParse/Gen.hs
+++ b/test/Zifter/OptParse/Gen.hs
@@ -2,9 +2,9 @@
 
 module Zifter.OptParse.Gen where
 
-import Zifter.OptParse.Types
+import TestImport
 
-import Test.Validity
+import Zifter.OptParse.Types
 
 instance GenUnchecked OutputMode
 
diff --git a/test/Zifter/RecurseSpec.hs b/test/Zifter/RecurseSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Zifter/RecurseSpec.hs
@@ -0,0 +1,21 @@
+module Zifter.RecurseSpec
+    ( spec
+    ) where
+
+import TestImport
+
+import Zifter.Recurse
+
+spec :: Spec
+spec =
+    describe "hiddenIn" $ do
+        it "correctly identifies a subdirectory of .stack-work as hidden" $ do
+            rp <- parseAbsDir "/home/user/project/"
+            af <-
+                parseAbsFile
+                    "/home/user/project/.stack-work/downloaded/abcxyz/zift.hs"
+            af `shouldSatisfy` hiddenIn rp
+        it "correctly identifies a regular subdirectory as not hidden" $ do
+            rp <- parseAbsDir "/home/user/project/"
+            af <- parseAbsFile "/home/user/project/subdir/zift.hs"
+            af `shouldNotSatisfy` hiddenIn rp
diff --git a/test/Zifter/ZiftSpec.hs b/test/Zifter/ZiftSpec.hs
--- a/test/Zifter/ZiftSpec.hs
+++ b/test/Zifter/ZiftSpec.hs
@@ -5,17 +5,9 @@
     ( spec
     ) where
 
-import Test.Hspec
-import Test.QuickCheck
-import Test.Validity
-
-import Data.GenValidity.Path ()
-import Data.Maybe
-import Data.Monoid
+import TestImport
 
 import Control.Concurrent.STM
-
-import Path.IO
 
 import Zifter
 import Zifter.OptParse
diff --git a/test/ZifterSpec.hs b/test/ZifterSpec.hs
--- a/test/ZifterSpec.hs
+++ b/test/ZifterSpec.hs
@@ -4,14 +4,9 @@
     ( spec
     ) where
 
-import Test.Hspec
-import Test.QuickCheck
-import Test.Validity
-
-import Path.IO
+import TestImport
 
 import Control.Concurrent.STM
-import Data.GenValidity.Path ()
 
 import Zifter
 import Zifter.OptParse.Gen ()
diff --git a/zifter.cabal b/zifter.cabal
--- a/zifter.cabal
+++ b/zifter.cabal
@@ -1,73 +1,85 @@
-name: zifter
-version: 0.0.1.5
-cabal-version: >=1.10
-build-type: Simple
-license: MIT
-license-file: LICENSE
-copyright: Copyright: (c) 2017 Tom Sydney Kerckhove
-maintainer: syd.kerckhove@gmail.com
-homepage: http://cs-syd.eu
-synopsis: zifter
-description:
-    zifter
-category: Zift
-author: Tom Sydney Kerckhove
+-- This file has been generated from package.yaml by hpack version 0.20.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 312738552ea07cdd468fd82f5fa86345abfa17274a706308c2bd01fb5b06d3fa
 
+name:           zifter
+version:        0.0.1.6
+synopsis:       zifter
+description:    zifter
+category:       Zift
+homepage:       http://cs-syd.eu
+author:         Tom Sydney Kerckhove
+maintainer:     syd.kerckhove@gmail.com
+copyright:      Copyright: (c) 2017 Tom Sydney Kerckhove
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
 library
-    exposed-modules:
-        Zifter
-        Zifter.OptParse
-        Zifter.OptParse.Types
-        Zifter.Recurse
-        Zifter.Script
-        Zifter.Script.Types
-        Zifter.Setup
-        Zifter.Setup.Types
-        Zifter.Types
-        Zifter.Zift
-        Zifter.Zift.Types
-    build-depends:
-        base >=4.9 && <=5,
-        ansi-terminal >=0.6 && <0.8,
-        async >=2.1 && <2.2,
-        directory >=1.2 && <1.4,
-        exceptions >=0.8 && <0.9,
-        filepath >=1.4 && <1.5,
-        optparse-applicative >=0.13 && <0.15,
-        path >=0.5 && <0.7,
-        path-io >1.2 && <1.4,
-        process >=1.4 && <1.7,
-        safe >=0.3 && <0.4,
-        stm >=2.4 && <2.5,
-        validity >=0.3 && <0.5,
-        validity-path >=0.1 && <0.3
-    default-language: Haskell2010
-    hs-source-dirs: src/
-    ghc-options: -Wall
+  hs-source-dirs:
+      src/
+  ghc-options: -Wall
+  build-depends:
+      ansi-terminal >=0.6 && <0.8
+    , async >=2.1 && <2.2
+    , base >=4.9 && <=5
+    , directory >=1.2 && <1.4
+    , exceptions >=0.8 && <0.9
+    , filepath >=1.4 && <1.5
+    , optparse-applicative >=0.13 && <0.15
+    , path >=0.6 && <0.7
+    , path-io >1.3 && <1.4
+    , process >=1.4 && <1.7
+    , safe >=0.3 && <0.4
+    , stm >=2.4 && <2.5
+    , validity >=0.3 && <0.5
+    , validity-path >=0.1 && <0.3
+  exposed-modules:
+      Zifter
+      Zifter.OptParse
+      Zifter.OptParse.Types
+      Zifter.Recurse
+      Zifter.Script
+      Zifter.Script.Types
+      Zifter.Setup
+      Zifter.Setup.Types
+      Zifter.Types
+      Zifter.Zift
+      Zifter.Zift.Types
+  other-modules:
+      Paths_zifter
+  default-language: Haskell2010
 
 test-suite zifter-test
-    type: exitcode-stdio-1.0
-    main-is: Spec.hs
-    build-depends:
-        base >=4.9 && <=5,
-        zifter -any,
-        QuickCheck >=2.9 && <2.11,
-        colour >=2.3 && <2.4,
-        genvalidity >=0.3 && <0.5,
-        genvalidity-hspec >=0.3 && <0.6,
-        genvalidity-path >=0.1 && <0.3,
-        hspec -any,
-        path -any,
-        path-io -any,
-        stm -any,
-        ansi-terminal -any,
-        directory -any
-    default-language: Haskell2010
-    hs-source-dirs: test/
-    other-modules:
-        ZifterSpec
-        Zifter.Gen
-        Zifter.ZiftSpec
-        Zifter.Zift.Gen
-        Zifter.OptParse.Gen
-    ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  hs-source-dirs:
+      test/
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
+  build-depends:
+      QuickCheck >=2.9 && <2.11
+    , ansi-terminal
+    , base >=4.9 && <=5
+    , colour >=2.3 && <2.4
+    , directory
+    , genvalidity >=0.3 && <0.5
+    , genvalidity-hspec >=0.3 && <0.6
+    , genvalidity-path >=0.1 && <0.3
+    , hspec
+    , path
+    , path-io
+    , stm
+    , zifter
+  other-modules:
+      TestImport
+      Zifter.Gen
+      Zifter.OptParse.Gen
+      Zifter.RecurseSpec
+      Zifter.Zift.Gen
+      Zifter.ZiftSpec
+      ZifterSpec
+      Paths_zifter
+  default-language: Haskell2010
