diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
 # Changelog
 
+## [0.30.0.0] - 2026-09-02
+
+### Changed
+
+* `scenarioDir`, `scenarioDirRecur` and `scenarioDirOfDirs` take a `Path b Dir`
+  and hand the callback a `Path Rel File` or a `Path Rel Dir`, relative to that
+  directory, where all three took and gave a `FilePath`.
+  Pass `[reldir|test_resources/scenarios|]` for the directory, and join the
+  scenario to it to read it.
+
+  Test descriptions are unchanged, so a `--filter` over them still selects the
+  same tests.
+
 ## [0.29.0.0] - 2026-08-19
 
 ### Added
diff --git a/src/Test/Syd/Def/Scenario.hs b/src/Test/Syd/Def/Scenario.hs
--- a/src/Test/Syd/Def/Scenario.hs
+++ b/src/Test/Syd/Def/Scenario.hs
@@ -19,15 +19,20 @@
 -- instead, because that usually means the scenario files were omitted by
 -- accident.
 --
+-- The scenario is given relative to the directory, so it is the name to say the
+-- test is about and joining it to the directory is what reads it. Neither has to
+-- be recovered from the other.
+--
 -- Example:
 --
--- >   scenarioDir "test_resources/even" $ \fp ->
+-- >   let dir = [reldir|test_resources/even|]
+-- >   scenarioDir dir $ \rf ->
 -- >     it "contains an even number" $ do
--- >       s <- readFile fp
+-- >       s <- readFile (fromRelFile (dir </> rf))
 -- >       n <- readIO s
 -- >       (n :: Int) `shouldSatisfy` even
-scenarioDir :: FilePath -> (FilePath -> TestDefM outers inner ()) -> TestDefM outers inner ()
-scenarioDir = scenarioDirHelper "files" (fmap (map fromRelFile . snd) . listDirRel)
+scenarioDir :: Path b Dir -> (Path Rel File -> TestDefM outers inner ()) -> TestDefM outers inner ()
+scenarioDir = scenarioDirHelper "files" (fmap snd . listDirRel)
 
 -- | Define a test for each file in the given directory, recursively.
 --
@@ -37,13 +42,14 @@
 --
 -- Example:
 --
--- >   scenarioDirRecur "test_resources/odd" $ \fp ->
+-- >   let dir = [reldir|test_resources/odd|]
+-- >   scenarioDirRecur dir $ \rf ->
 -- >     it "contains an odd number" $ do
--- >       s <- readFile fp
+-- >       s <- readFile (fromRelFile (dir </> rf))
 -- >       n <- readIO s
 -- >       (n :: Int) `shouldSatisfy` odd
-scenarioDirRecur :: FilePath -> (FilePath -> TestDefM outers inner ()) -> TestDefM outers inner ()
-scenarioDirRecur = scenarioDirHelper "files" (fmap (map fromRelFile . snd) . listDirRecurRel)
+scenarioDirRecur :: Path b Dir -> (Path Rel File -> TestDefM outers inner ()) -> TestDefM outers inner ()
+scenarioDirRecur = scenarioDirHelper "files" (fmap snd . listDirRecurRel)
 
 -- | Define a test for each subdirectory of the given directory.
 --
@@ -57,32 +63,38 @@
 --
 -- Example:
 --
--- >   scenarioDirOfDirs "test_resources/same" $ \fp ->
+-- >   let dir = [reldir|test_resources/same|]
+-- >   scenarioDirOfDirs dir $ \rd ->
 -- >     it "contains two files with the same contents" $ do
--- >       a <- readFile (fp </> "a")
--- >       b <- readFile (fp </> "b")
+-- >       a <- readFile (fromRelFile (dir </> rd </> [relfile|a|]))
+-- >       b <- readFile (fromRelFile (dir </> rd </> [relfile|b|]))
 -- >       a `shouldBe` b
-scenarioDirOfDirs :: FilePath -> (FilePath -> TestDefM outers inner ()) -> TestDefM outers inner ()
-scenarioDirOfDirs =
-  scenarioDirHelper
-    "directories"
-    (fmap (map (FP.dropTrailingPathSeparator . fromRelDir) . fst) . listDirRel)
+scenarioDirOfDirs :: Path b Dir -> (Path Rel Dir -> TestDefM outers inner ()) -> TestDefM outers inner ()
+scenarioDirOfDirs = scenarioDirHelper "directories" (fmap fst . listDirRel)
 
 scenarioDirHelper ::
   -- | What the lister looks for, for the description of the failing test that
   -- an empty scenario directory produces.
   String ->
   -- | The scenarios, relative to the given directory
-  (Path Abs Dir -> IO [FilePath]) ->
-  FilePath ->
-  (FilePath -> TestDefM outers inner ()) ->
+  (Path Abs Dir -> IO [Path Rel t]) ->
+  Path b Dir ->
+  (Path Rel t -> TestDefM outers inner ()) ->
   TestDefM outers inner ()
-scenarioDirHelper noun lister dp func =
-  describe dp $ do
-    ad <- liftIO $ resolveDir' dp
+scenarioDirHelper noun lister dir func =
+  describe (described dir) $ do
+    ad <- liftIO $ makeAbsolute dir
     ss <- liftIO $ fmap (fromMaybe []) $ forgivingAbsence $ lister ad
     if null ss
       then it (unwords ["has scenario", noun]) $ \_ ->
-        (expectationFailure $ unwords ["No scenario", noun, "found in", dp] :: IO ())
+        (expectationFailure $ unwords ["No scenario", noun, "found in", described dir] :: IO ())
       else forM_ ss $ \s ->
-        describe s $ func (dp FP.</> s)
+        describe (described s) $ func s
+
+-- | A path as a test description.
+--
+-- The separator a directory's rendering ends in comes off, so that a scenario
+-- reads the same whether it is a file or a directory, and so that these
+-- descriptions are the ones they were before the scenarios became typed.
+described :: Path b t -> String
+described = FP.dropTrailingPathSeparator . toFilePath
diff --git a/src/Test/Syd/Def/Specify.hs b/src/Test/Syd/Def/Specify.hs
--- a/src/Test/Syd/Def/Specify.hs
+++ b/src/Test/Syd/Def/Specify.hs
@@ -93,9 +93,9 @@
 -- > describe "readFile and writeFile" $
 -- >     it "reads back what it wrote for this example" $ do
 -- >         let cts = "hello world"
--- >         let fp = "test.txt"
--- >         writeFile fp cts
--- >         cts' <- readFile fp
+-- >         let file = [relfile|test.txt|]
+-- >         writeFile (fromRelFile file) cts
+-- >         cts' <- readFile (fromRelFile file)
 -- >         cts' `shouldBe` cts
 --
 --
@@ -111,10 +111,10 @@
 --
 -- > describe "readFile and writeFile" $
 -- >     it "reads back what it wrote for any example" $ do
--- >         forAllValid $ \fp ->
+-- >         forAllValid $ \file ->
 -- >             forAllValid $ \cts -> do
--- >                 writeFile fp cts
--- >                 cts' <- readFile fp
+-- >                 writeFile (fromRelFile file) cts
+-- >                 cts' <- readFile (fromRelFile file)
 -- >                 cts' `shouldBe` cts
 --
 --
@@ -137,9 +137,9 @@
 -- > in around setUpTempDir $ describe "readFile and writeFile" $
 -- >     it "reads back what it wrote for this example" $ \tempDir -> do
 -- >         let cts = "hello world"
--- >         let fp = tempDir </> "test.txt"
--- >         writeFile fp cts
--- >         cts' <- readFile fp
+-- >         let file = tempDir </> [relfile|test.txt|]
+-- >         writeFile (fromAbsFile file) cts
+-- >         cts' <- readFile (fromAbsFile file)
 -- >         cts' `shouldBe` cts
 --
 --
@@ -158,9 +158,9 @@
 -- > in around setUpTempDir $ describe "readFile and writeFile" $
 -- >     it "reads back what it wrote for this example" $ \tempDir ->
 -- >         property $ \cts -> do
--- >             let fp = tempDir </> "test.txt"
--- >             writeFile fp cts
--- >             cts' <- readFile fp
+-- >             let file = tempDir </> [relfile|test.txt|]
+-- >             writeFile (fromAbsFile file) cts
+-- >             cts' <- readFile (fromAbsFile file)
 -- >             cts' `shouldBe` cts
 it ::
   forall outers inner test.
@@ -239,9 +239,9 @@
 -- > in aroundAll setUpTempDir describe "readFile and writeFile" $
 -- >     itWithOuter "reads back what it wrote for this example" $ \tempDir -> do
 -- >         let cts = "hello world"
--- >         let fp = tempDir </> "test.txt"
--- >         writeFile fp cts
--- >         cts' <- readFile fp
+-- >         let file = tempDir </> [relfile|test.txt|]
+-- >         writeFile (fromAbsFile file) cts
+-- >         cts' <- readFile (fromAbsFile file)
 -- >         cts' `shouldBe` cts
 --
 --
@@ -258,11 +258,11 @@
 --
 -- > let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
 -- > in aroundAll setUpTempDir describe "readFile and writeFile" $
--- >     itWithouter "reads back what it wrote for this example" $ \tempDir ->
+-- >     itWithOuter "reads back what it wrote for this example" $ \tempDir ->
 -- >         property $ \cts -> do
--- >             let fp = tempDir </> "test.txt"
--- >             writeFile fp cts
--- >             cts' <- readFile fp
+-- >             let file = tempDir </> [relfile|test.txt|]
+-- >             writeFile (fromAbsFile file) cts
+-- >             cts' <- readFile (fromAbsFile file)
 -- >             cts' `shouldBe` cts
 itWithOuter ::
   (HasCallStack, IsTest test, Arg1 test ~ inner, Arg2 test ~ outer) =>
@@ -336,9 +336,9 @@
 -- > let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
 -- > in aroundAll setUpTempDir describe "readFile and writeFile" $ before (pure "hello world") $
 -- >     itWithBoth "reads back what it wrote for this example" $ \tempDir cts -> do
--- >         let fp = tempDir </> "test.txt"
--- >         writeFile fp cts
--- >         cts' <- readFile fp
+-- >         let file = tempDir </> [relfile|test.txt|]
+-- >         writeFile (fromAbsFile file) cts
+-- >         cts' <- readFile (fromAbsFile file)
 -- >         cts' `shouldBe` cts
 --
 --
@@ -354,12 +354,12 @@
 -- ===== IO property test
 --
 -- > let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
--- > in aroundAll setUpTempDir describe "readFile and writeFile" $ before (pure "test.txt") $
+-- > in aroundAll setUpTempDir describe "readFile and writeFile" $ before (pure [relfile|test.txt|]) $
 -- >     itWithBoth "reads back what it wrote for this example" $ \tempDir fileName ->
 -- >         property $ \cts -> do
--- >             let fp = tempDir </> fileName
--- >             writeFile fp cts
--- >             cts' <- readFile fp
+-- >             let file = tempDir </> fileName
+-- >             writeFile (fromAbsFile file) cts
+-- >             cts' <- readFile (fromAbsFile file)
 -- >             cts' `shouldBe` cts
 itWithBoth ::
   ( HasCallStack,
diff --git a/sydtest.cabal b/sydtest.cabal
--- a/sydtest.cabal
+++ b/sydtest.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           sydtest
-version:        0.29.0.0
+version:        0.30.0.0
 synopsis:       A modern testing framework for Haskell with good defaults and advanced testing features.
 description:    A modern testing framework for Haskell with good defaults and advanced testing features. Sydtest aims to make the common easy and the hard possible. See https://github.com/NorfairKing/sydtest#readme for more information.
 category:       Testing
