diff --git a/shake-plus.cabal b/shake-plus.cabal
--- a/shake-plus.cabal
+++ b/shake-plus.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: a0d7d5de64c4e73aa6c28731b41b9e9d95c762545d9f6b2ee3fa8e062dc79a05
+-- hash: 72a456ccc4bf86f1d6a5c4a2567d6582c53f2c8bb7b28bc2d7c4feb318d7c598
 
 name:           shake-plus
-version:        0.0.1.2
+version:        0.0.2.0
 synopsis:       Re-export of Shake using well-typed paths and ReaderT.
 description:    Re-export of Shake using well-typed paths and ReaderT. This is an early release so some things may be missing or broken but so far the conveniences have been worth it.
 category:       development, shake
@@ -32,6 +32,7 @@
       Development.Shake.Plus.Env
       Development.Shake.Plus.File
       Development.Shake.Plus.FileRules
+      Development.Shake.Plus.Loaders
       Development.Shake.Plus.Oracle
       Development.Shake.Plus.Temp
   other-modules:
@@ -45,4 +46,5 @@
     , path
     , rio
     , shake
+    , within
   default-language: Haskell2010
diff --git a/src/Development/Shake/Plus.hs b/src/Development/Shake/Plus.hs
--- a/src/Development/Shake/Plus.hs
+++ b/src/Development/Shake/Plus.hs
@@ -4,12 +4,14 @@
 , module Development.Shake.Plus.Directory
 , module Development.Shake.Plus.File
 , module Development.Shake.Plus.FileRules
+, module Development.Shake.Plus.Loaders
 , module Development.Shake.Plus.Oracle
 ) where
 
 import Development.Shake.Plus.Cache
 import Development.Shake.Plus.Core
+import Development.Shake.Plus.Directory
 import Development.Shake.Plus.File
 import Development.Shake.Plus.FileRules
-import Development.Shake.Plus.Directory
+import Development.Shake.Plus.Loaders
 import Development.Shake.Plus.Oracle
diff --git a/src/Development/Shake/Plus/Core.hs b/src/Development/Shake/Plus/Core.hs
--- a/src/Development/Shake/Plus/Core.hs
+++ b/src/Development/Shake/Plus/Core.hs
@@ -10,10 +10,15 @@
 , ShakePlus
 , runRAction
 , runShakePlus
+, Development.Shake.Action
+, Development.Shake.Rules
+, Development.Shake.FilePattern
+, Development.Shake.shake
+, Development.Shake.shakeOptions
 ) where
 
 import Control.Exception
-import Development.Shake (Action, Rules)
+import Development.Shake (Action, Rules, FilePattern, shake, shakeOptions)
 import RIO
 
 -- | Monads in which `Action`s may be embedded.
diff --git a/src/Development/Shake/Plus/Directory.hs b/src/Development/Shake/Plus/Directory.hs
--- a/src/Development/Shake/Plus/Directory.hs
+++ b/src/Development/Shake/Plus/Directory.hs
@@ -2,6 +2,7 @@
   doesFileExist
 , doesDirectoryExist
 , getDirectoryFiles
+, getDirectoryFilesWithin
 , getDirectoryDirs
 , getDirectoryFilesIO
 ) where
@@ -12,6 +13,7 @@
 import Development.Shake (FilePattern)
 import RIO
 import Path
+import Within
 
 -- | Lifted version of `Development.Shake.doesFileExist` using well-typed `Path`s.
 doesFileExist :: MonadAction m => Path b File -> m Bool
@@ -24,6 +26,12 @@
 -- | Lifted version of `Development.Shake.getDirectoryFiles` using well-typed `Path`s.
 getDirectoryFiles :: MonadAction m => Path b Dir -> [FilePattern] -> m [Path Rel File]
 getDirectoryFiles x y = liftAction $ traverse (liftIO . parseRelFile) =<< Development.Shake.getDirectoryFiles (toFilePath x) y
+
+-- | Like `getDirectoryFiles`, but returns `Within` values.
+getDirectoryFilesWithin :: MonadAction m => Path Rel Dir -> [FilePattern] -> m [Within Rel File]
+getDirectoryFilesWithin x pat = do
+  xs <- getDirectoryFiles x pat
+  return ((`within` x) <$> xs)
 
 -- | Lifted version of `Development.Shake.getDirectoryDirs` using well-typed `Path`s.
 getDirectoryDirs :: MonadAction m => Path b Dir -> m [Path Rel Dir]
diff --git a/src/Development/Shake/Plus/File.hs b/src/Development/Shake/Plus/File.hs
--- a/src/Development/Shake/Plus/File.hs
+++ b/src/Development/Shake/Plus/File.hs
@@ -3,9 +3,15 @@
 , copyFileChanged
 , readFile'
 , readFileLines
+, readFileIn'
+, readFileWithin
 , writeFile'
 , writeFileLines
+, writeFileIn'
+, writeFileWithin
 , writeFileChanged
+, writeFileChangedIn
+, writeFileChangedWithin
 , removeFiles
 , removeFilesAfter
 ) where
@@ -17,6 +23,7 @@
 import RIO
 import qualified RIO.Text as T
 import Path
+import Within
 
 -- | Lifted version of `Development.Shake.copyFile` with well-typed `Path`s.
 copyFile' :: (MonadAction m, Partial) => Path Rel File -> Path Rel File -> m ()
@@ -34,6 +41,15 @@
 readFileLines :: (MonadAction m, Partial) => Path Rel File -> m [Text]
 readFileLines = liftAction . fmap (fmap T.pack) . Development.Shake.readFileLines . toFilePath
 
+-- | Like `readFile'`, but with an argument for the parent directory. Used for symmetry with
+-- the way `Development.Shake.getDirectoryFiles` takes arguments.
+readFileIn' :: MonadAction m => Path Rel Dir -> Path Rel File -> m Text
+readFileIn' x y = readFile' $ x </> y
+
+-- | Like 'readFile'`, but accepts a `Within` value.
+readFileWithin :: MonadAction m => Within Rel File -> m Text
+readFileWithin = readFile' . fromWithin
+
 -- | Lifted version of `Development.Shake.writeFile` with well-typed `Path`.
 writeFile' :: (MonadAction m, Partial) => Path Rel File -> Text -> m ()
 writeFile' x y = liftAction $ Development.Shake.writeFile' (toFilePath x) (T.unpack y)
@@ -42,9 +58,27 @@
 writeFileLines :: (MonadAction m, Partial) => Path Rel File -> [Text] -> m ()
 writeFileLines x y = liftAction $ Development.Shake.writeFileLines (toFilePath x) (fmap T.unpack y)
 
+-- | Like `writeFile'`, but with an argument for the parent directory. Used for symmetry with
+-- the way `Development.Shake.getDirectoryFiles` takes arguments.
+writeFileIn' :: MonadAction m => Path Rel Dir -> Path Rel File -> Text -> m ()
+writeFileIn' x y = writeFile' $ x </> y
+
+-- | Like 'writeFile'`, but accepts a `Within` value.
+writeFileWithin :: MonadAction m => Within Rel File -> Text -> m ()
+writeFileWithin = writeFile' . fromWithin
+
 -- | Lifted version of `Development.Shake.writeFileChanged` with well-typed `Path`.
 writeFileChanged :: (MonadAction m, Partial) => Path b File -> Text -> m ()
 writeFileChanged x y = liftAction $ Development.Shake.writeFileChanged (toFilePath x) (T.unpack y)
+
+-- | Like `writeFileChanged'`, but with an argument for the parent directory. Used for symmetry with
+-- the way `Development.Shake.getDirectoryFiles` takes arguments.
+writeFileChangedIn :: MonadAction m => Path Rel Dir -> Path Rel File -> Text -> m ()
+writeFileChangedIn x y = writeFileChanged $ x </> y
+
+-- | Like `writeFileChanged'`, but accepts a `Within` value.
+writeFileChangedWithin :: MonadAction m => Within Rel File -> Text -> m ()
+writeFileChangedWithin = writeFileChanged . fromWithin 
 
 -- | Lifted version of `Development.Shake.removeFiles` with well-typed `Path`.
 removeFiles :: MonadAction m => Path b File -> [FilePattern] -> m ()
diff --git a/src/Development/Shake/Plus/FileRules.hs b/src/Development/Shake/Plus/FileRules.hs
--- a/src/Development/Shake/Plus/FileRules.hs
+++ b/src/Development/Shake/Plus/FileRules.hs
@@ -1,5 +1,12 @@
 module Development.Shake.Plus.FileRules (
   need
+, want
+, needP
+, wantP
+, needIn
+, wantIn
+, needWithin
+, wantWithin
 , (%>)
 , (|%>)
 , phony
@@ -11,11 +18,44 @@
 import Development.Shake (FilePattern)
 import RIO
 import Path
+import Within
 
+-- | Lifted version of `Development.Shake.need`, This still uses `String`s
+-- because it may refer to a phony rule. For the `Path` specific version
+-- use `needP`
+need :: MonadAction m => [String] -> m ()
+need = liftAction . Development.Shake.need
+
+-- | Lifted version of `Development.Shake.want`. This still uses `String`s
+-- because it may refer to a phony rule. For the `Path` specific version
+-- use wantP.
+want :: MonadRules m => [String] -> m ()
+want = liftRules . Development.Shake.want
+
 -- | Lifted version of `Development.Shake.need` using well-typed `Path`s
-need :: (MonadAction m, Partial) => [Path Rel File] -> m ()
-need = liftAction . Development.Shake.need . map toFilePath
+needP :: (MonadAction m, Partial) => [Path Rel File] -> m ()
+needP = need . map toFilePath
 
+-- | Lifted version of `Development.Shake.want` using well-typed `Path`s
+wantP :: MonadRules m => [Path Rel File] -> m ()
+wantP = want . map toFilePath
+
+-- | Like `needP`, but accepts `Path`s relative to the first argument.
+needIn :: MonadAction m => Path Rel Dir -> [Path Rel File] -> m ()
+needIn x = needP . fmap (x </>)
+
+-- | Like `wantP`, but accepts `Path`s relative to the first argument.
+wantIn :: MonadRules m => Path Rel Dir -> [Path Rel File] -> m ()
+wantIn x = wantP . fmap (x </>)
+
+-- | Like `needP`, but accepts `Within` values.
+needWithin :: MonadAction m => [Within Rel File] -> m ()
+needWithin = needP . map fromWithin
+
+-- | Like `wantP`, but accepts `Within` values.
+wantWithin :: MonadRules m => [Within Rel File] -> m ()
+wantWithin = wantP . map fromWithin
+
 -- | Lifted version of `Development.Shake.%>` using well-typed `Path`s
 (%>) :: (Partial, MonadReader r m, MonadRules m) => FilePattern -> (Path Rel File -> RAction r ()) -> m ()
 (%>) x ract = ask >>= \r -> liftRules $ x Development.Shake.%> (runRAction r . (ract <=< parseRelFile))
@@ -24,6 +64,6 @@
 (|%>) :: (Partial, MonadReader r m, MonadRules m) => [FilePattern] -> (Path Rel File -> RAction r ()) -> m ()
 (|%>) x ract = ask >>= \r -> liftRules $ x Development.Shake.|%> (runRAction r . (ract <=< parseRelFile))
 
--- | Lifted version of `Development.Shake.phony` using well-typed `Path`s
+-- | Lifted version of `Development.Shake.phony` using well-typed `Path`s and `RAction`
 phony :: (MonadReader r m, MonadRules m) => String -> RAction r () -> m ()
 phony x ract = ask >>= \r -> liftRules $ Development.Shake.phony x $ runRAction r ract
diff --git a/src/Development/Shake/Plus/Loaders.hs b/src/Development/Shake/Plus/Loaders.hs
new file mode 100644
--- /dev/null
+++ b/src/Development/Shake/Plus/Loaders.hs
@@ -0,0 +1,42 @@
+module Development.Shake.Plus.Loaders (
+  loadSortFilterApply
+, loadSortFilterApplyW
+) where
+
+import Development.Shake.Plus.Core
+import Development.Shake.Plus.Directory
+import RIO
+import RIO.List
+import Path
+import Within
+
+traverseToSnd :: Functor f => (a -> f b) -> a -> f (a, b)
+traverseToSnd f a = (a,) <$> f a
+
+-- | Batch loading function. Loads all items detected by the filtepattern and provides parameters
+-- for sorting, filtering and a simple transformation via an endofunction. Returns a list of values
+-- indexed by their source `Path`.
+loadSortFilterApply :: (MonadAction m, Ord b)
+                    => (Path Rel File -> m a) -- ^ A loading function, (i.e readFile' or a custom `readMarkdownFile, readJPG etc that returns a type you can sort/filter on.)
+                    -> Path Rel Dir -- ^ The path to search in.
+                    -> [FilePattern] -- ^ A filepattern to match on.
+                    -> (a -> b) -- ^ The value to sortOn .
+                    -> (a -> Bool) -- ^ A filtering predicate.
+                    -> (a -> a) -- ^ A simple endotransformation.
+                    -> m [(Path Rel File, a)]
+loadSortFilterApply l dir pat s f e = do
+  xs <- getDirectoryFiles dir pat >>= mapM (traverseToSnd l)
+  return $ fmap (second e) $ sortOn (s . snd) $ filter (f . snd) $ xs
+
+-- | Like `loadSortFilterApply`, but returns `Within` values.
+loadSortFilterApplyW :: (MonadAction m, Ord b)
+                     => (Within Rel File -> m a) -- ^ A loading function, (i.e readFile' or a custom `readMarkdownFile, readJPG etc that returns a type you can sort/filter on.)
+                     -> Path Rel Dir -- ^ The path to search in.
+                     -> [FilePattern] -- ^ A filepattern to match on.
+                     -> (a -> b) -- ^ The value to sortOn .
+                     -> (a -> Bool) -- ^ A filtering predicate.
+                     -> (a -> a) -- ^ A simple endotransformation.
+                     -> m [(Within Rel File, a)]
+loadSortFilterApplyW l dir pat s f e = do
+  xs <- getDirectoryFilesWithin dir pat >>= mapM (traverseToSnd l)
+  return $ fmap (second e) $ sortOn (s . snd) $ filter (f . snd) $ xs
